Commit 85c1adf9 authored by Thomas Van Lenten's avatar Thomas Van Lenten Committed by GitHub

Merge pull request #2053 from thomasvl/improve_root_registry_wiring

Make Root's +extensionRegistry generation smarter.
parents d00cab0f 13a41246
......@@ -534,6 +534,7 @@ objectivec_EXTRA_DIST= \
objectivec/Tests/GPBTestUtilities.h \
objectivec/Tests/GPBTestUtilities.m \
objectivec/Tests/GPBUnittestProtos.m \
objectivec/Tests/GPBUnittestProtos2.m \
objectivec/Tests/GPBUnknownFieldSetTest.m \
objectivec/Tests/GPBUtilitiesTests.m \
objectivec/Tests/GPBWellKnownTypesTest.m \
......@@ -555,6 +556,13 @@ objectivec_EXTRA_DIST= \
objectivec/Tests/text_format_map_unittest_data.txt \
objectivec/Tests/text_format_unittest_data.txt \
objectivec/Tests/unittest_cycle.proto \
objectivec/Tests/unittest_extension_chain_a.proto \
objectivec/Tests/unittest_extension_chain_b.proto \
objectivec/Tests/unittest_extension_chain_c.proto \
objectivec/Tests/unittest_extension_chain_d.proto \
objectivec/Tests/unittest_extension_chain_e.proto \
objectivec/Tests/unittest_extension_chain_f.proto \
objectivec/Tests/unittest_extension_chain_g.proto \
objectivec/Tests/unittest_objc.proto \
objectivec/Tests/unittest_objc_startup.proto \
objectivec/Tests/unittest_runtime_proto2.proto \
......
#!/bin/bash
#!/bin/bash -eu
# Invoked by the Xcode projects to build the protos needed for the unittests.
set -eu
readonly OUTPUT_DIR="${PROJECT_DERIVED_FILE_DIR}/protos"
# -----------------------------------------------------------------------------
# Helper for bailing.
die() {
echo "Error: $1"
exit 2
}
# -----------------------------------------------------------------------------
# What to do.
case "${ACTION}" in
"")
......@@ -26,12 +25,19 @@ case "${ACTION}" in
;;
esac
# Move to the top of the protobuf directories.
cd "${SRCROOT}/.."
# -----------------------------------------------------------------------------
# Ensure the output dir exists
mkdir -p "${OUTPUT_DIR}/google/protobuf"
# -----------------------------------------------------------------------------
# Move to the top of the protobuf directories and ensure there is a protoc
# binary to use.
cd "${SRCROOT}/.."
[[ -x src/protoc ]] || \
die "Could not find the protoc binary; make sure you have built it (objectivec/DevTools/full_mac_build.sh -h)."
# -----------------------------------------------------------------------------
# See the compiler or proto files have changed.
RUN_PROTOC=no
if [[ ! -d "${OUTPUT_DIR}" ]] ; then
RUN_PROTOC=yes
......@@ -50,7 +56,7 @@ else
# Find the oldest output file.
readonly OldestOutput=$(find \
"${OUTPUT_DIR}" \
-type f -print0 \
-type f -name "*pbobjc.[hm]" -print0 \
| xargs -0 stat -f "%m %N" \
| sort -n -r | tail -n1 | cut -f2- -d" ")
# If the newest input is newer than the oldest output, regenerate.
......@@ -64,8 +70,27 @@ if [[ "${RUN_PROTOC}" != "yes" ]] ; then
exit 0
fi
# Ensure the output dir exists
mkdir -p "${OUTPUT_DIR}/google/protobuf"
# -----------------------------------------------------------------------------
# Prune out all the files from previous generations to ensure we only have
# current ones.
find "${OUTPUT_DIR}" \
-type f -name "*pbobjc.[hm]" -print0 \
| xargs -0 rm -rf
# -----------------------------------------------------------------------------
# Helper to invoke protoc
compile_protos() {
src/protoc \
--objc_out="${OUTPUT_DIR}/google/protobuf" \
--proto_path=src/google/protobuf/ \
--proto_path=src \
"$@"
}
# -----------------------------------------------------------------------------
# Generate most of the proto files that exist in the C++ src tree. Several
# are used in the tests, but the extra don't hurt in that they ensure ObjC
# sources can be generated from them.
CORE_PROTO_FILES=(
src/google/protobuf/unittest_arena.proto
......@@ -90,23 +115,12 @@ CORE_PROTO_FILES=(
src/google/protobuf/map_lite_unittest.proto
src/google/protobuf/map_proto2_unittest.proto
src/google/protobuf/map_unittest.proto
)
# The unittest_custom_options.proto extends the messages in descriptor.proto
# so we build it in to test extending in general. The library doesn't provide
# a descriptor as it doesn't use the classes/enums.
CORE_PROTO_FILES+=(
# The unittest_custom_options.proto extends the messages in descriptor.proto
# so we build it in to test extending in general. The library doesn't provide
# a descriptor as it doesn't use the classes/enums.
src/google/protobuf/descriptor.proto
)
compile_protos() {
src/protoc \
--objc_out="${OUTPUT_DIR}/google/protobuf" \
--proto_path=src/google/protobuf/ \
--proto_path=src \
"$@"
}
# Note: there is overlap in package.Message names between some of the test
# files, so they can't be generated all at once. This works because the overlap
# isn't linked into a single binary.
......@@ -114,10 +128,18 @@ for a_proto in "${CORE_PROTO_FILES[@]}" ; do
compile_protos "${a_proto}"
done
# Objective C specific testing protos.
# -----------------------------------------------------------------------------
# Generate the Objective C specific testing protos.
compile_protos \
--proto_path="objectivec/Tests" \
objectivec/Tests/unittest_cycle.proto \
objectivec/Tests/unittest_extension_chain_a.proto \
objectivec/Tests/unittest_extension_chain_b.proto \
objectivec/Tests/unittest_extension_chain_c.proto \
objectivec/Tests/unittest_extension_chain_d.proto \
objectivec/Tests/unittest_extension_chain_e.proto \
objectivec/Tests/unittest_extension_chain_f.proto \
objectivec/Tests/unittest_extension_chain_g.proto \
objectivec/Tests/unittest_runtime_proto2.proto \
objectivec/Tests/unittest_runtime_proto3.proto \
objectivec/Tests/unittest_objc.proto \
......
......@@ -65,6 +65,7 @@
F4E675A11B21D0000054530B /* Struct.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675911B21D0000054530B /* Struct.pbobjc.m */; };
F4E675A31B21D0000054530B /* Type.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675931B21D0000054530B /* Type.pbobjc.m */; };
F4E675A51B21D0000054530B /* Wrappers.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675951B21D0000054530B /* Wrappers.pbobjc.m */; };
F4F8D8831D789FD9002CE128 /* GPBUnittestProtos2.m in Sources */ = {isa = PBXBuildFile; fileRef = F4F8D8811D789FCE002CE128 /* GPBUnittestProtos2.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
......@@ -211,6 +212,7 @@
F4E675AB1B21D05C0054530B /* struct.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = struct.proto; path = ../src/google/protobuf/struct.proto; sourceTree = "<group>"; };
F4E675AC1B21D05C0054530B /* type.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = type.proto; path = ../src/google/protobuf/type.proto; sourceTree = "<group>"; };
F4E675AD1B21D05C0054530B /* wrappers.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = wrappers.proto; path = ../src/google/protobuf/wrappers.proto; sourceTree = "<group>"; };
F4F8D8811D789FCE002CE128 /* GPBUnittestProtos2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnittestProtos2.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
......@@ -408,6 +410,7 @@
7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */,
7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */,
8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */,
F4F8D8811D789FCE002CE128 /* GPBUnittestProtos2.m */,
7461B6B80F94FDF900A0C422 /* GPBUnknownFieldSetTest.m */,
7461B6BA0F94FDF900A0C422 /* GPBUtilitiesTests.m */,
8B4248DB1A92933A00BC1EC6 /* GPBWellKnownTypesTest.m */,
......@@ -659,6 +662,7 @@
F4B51B1E1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm in Sources */,
F4487C7F1AAF62CD00531423 /* GPBMessageTests+Serialization.m in Sources */,
8B4248DC1A92933A00BC1EC6 /* GPBWellKnownTypesTest.m in Sources */,
F4F8D8831D789FD9002CE128 /* GPBUnittestProtos2.m in Sources */,
F4353D1D1AB8822D005A6198 /* GPBDescriptorTests.m in Sources */,
8B4248BB1A8C256A00BC1EC6 /* GPBSwiftTests.swift in Sources */,
5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */,
......
......@@ -73,6 +73,7 @@
F4E675D51B21D1620054530B /* Struct.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675C21B21D1440054530B /* Struct.pbobjc.m */; };
F4E675D61B21D1620054530B /* Type.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675C51B21D1440054530B /* Type.pbobjc.m */; };
F4E675D71B21D1620054530B /* Wrappers.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675C71B21D1440054530B /* Wrappers.pbobjc.m */; };
F4F8D8861D78A193002CE128 /* GPBUnittestProtos2.m in Sources */ = {isa = PBXBuildFile; fileRef = F4F8D8841D78A186002CE128 /* GPBUnittestProtos2.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
......@@ -234,6 +235,7 @@
F4E675DD1B21D1DE0054530B /* struct.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = struct.proto; path = ../src/google/protobuf/struct.proto; sourceTree = "<group>"; };
F4E675DE1B21D1DE0054530B /* type.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = type.proto; path = ../src/google/protobuf/type.proto; sourceTree = "<group>"; };
F4E675DF1B21D1DE0054530B /* wrappers.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = wrappers.proto; path = ../src/google/protobuf/wrappers.proto; sourceTree = "<group>"; };
F4F8D8841D78A186002CE128 /* GPBUnittestProtos2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnittestProtos2.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
......@@ -446,6 +448,7 @@
7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */,
7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */,
8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */,
F4F8D8841D78A186002CE128 /* GPBUnittestProtos2.m */,
7461B6B80F94FDF900A0C422 /* GPBUnknownFieldSetTest.m */,
7461B6BA0F94FDF900A0C422 /* GPBUtilitiesTests.m */,
8B4248E51A929C9900BC1EC6 /* GPBWellKnownTypesTest.m */,
......@@ -755,6 +758,7 @@
F4487C811AAF62FC00531423 /* GPBMessageTests+Serialization.m in Sources */,
8B4248E61A929C9900BC1EC6 /* GPBWellKnownTypesTest.m in Sources */,
F4353D1F1AB88243005A6198 /* GPBDescriptorTests.m in Sources */,
F4F8D8861D78A193002CE128 /* GPBUnittestProtos2.m in Sources */,
F4B51B1C1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm in Sources */,
8B4248B41A8BD96E00BC1EC6 /* GPBSwiftTests.swift in Sources */,
5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */,
......
......@@ -36,6 +36,7 @@
#import "google/protobuf/MapUnittest.pbobjc.h"
#import "google/protobuf/Unittest.pbobjc.h"
#import "google/protobuf/UnittestCycle.pbobjc.h"
#import "google/protobuf/UnittestObjcStartup.pbobjc.h"
#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
#import "google/protobuf/UnittestRuntimeProto3.pbobjc.h"
......@@ -49,11 +50,24 @@
// specific.
- (void)testStartupOrdering {
// Just have to create a message. Nothing else uses the classes from
// this file, so the first selector invoked on the class will initialize
// it, which also initializes the root.
// Message class/Root class initialization is a little tricky, so these just
// create some possible patterns that can be a problem. The messages don't
// have to be exercised, just creating them is enough to test. If there
// is a problem, the runtime should assert or hang.
//
// Note: the messages from these proto files should not be used in any other
// tests, that way when they are referenced here it will be the first use and
// initialization will take place now.
TestObjCStartupMessage *message = [TestObjCStartupMessage message];
XCTAssertNotNil(message);
CycleBaz *baz = [CycleBaz message];
CycleBar *bar = [CycleBar message];
CycleFoo *foo = [CycleFoo message];
XCTAssertNotNil(baz);
XCTAssertNotNil(bar);
XCTAssertNotNil(foo);
}
- (void)testProto2HasMethodSupport {
......
......@@ -62,3 +62,11 @@
#import "google/protobuf/UnittestPreserveUnknownEnum.pbobjc.m"
#import "google/protobuf/UnittestRuntimeProto2.pbobjc.m"
#import "google/protobuf/UnittestRuntimeProto3.pbobjc.m"
#import "google/protobuf/UnittestExtensionChainA.pbobjc.m"
#import "google/protobuf/UnittestExtensionChainB.pbobjc.m"
#import "google/protobuf/UnittestExtensionChainC.pbobjc.m"
#import "google/protobuf/UnittestExtensionChainD.pbobjc.m"
#import "google/protobuf/UnittestExtensionChainE.pbobjc.m"
// See GPBUnittestProtos2.m for for "UnittestExtensionChainF.pbobjc.m"
#import "google/protobuf/UnittestExtensionChainG.pbobjc.m"
// Protocol Buffers - Google's data interchange format
// Copyright 2016 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.
// This one file in the chain tests is compiled by itself to ensure if was
// generated with the extra #imports needed to pull in the indirect Root class
// used in its Root registry.
#import "google/protobuf/UnittestExtensionChainF.pbobjc.m"
......@@ -31,10 +31,8 @@ syntax = "proto2";
package protobuf_unittest;
// Cycles in the Message graph can cause problems for the mutable classes
// since the properties on the mutable class change types. This file just
// needs to generate source, and that source must compile, to ensure the
// generated source works for this sort of case.
// Cycles in the Message graph can cause problems for message class
// initialization order.
// You can't make a object graph that spans files, so this can only be done
// within a single proto file.
......
// Protocol Buffers - Google's data interchange format
// Copyright 2016 Google Inc. All rights reserved.
//
// 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;
import "google/protobuf/unittest.proto";
import "unittest_extension_chain_b.proto";
import "unittest_extension_chain_c.proto";
import "unittest_extension_chain_d.proto";
// The Root for this file should end up adding the local extension and merging
// in the extensions from D's Root (unittest and C will come via D's).
message ChainAMessage {
optional ChainBMessage b = 1;
optional ChainCMessage c = 2;
optional ChainDMessage d = 3;
}
extend TestAllExtensions {
optional int32 chain_a_extension = 10001;
}
// Protocol Buffers - Google's data interchange format
// Copyright 2016 Google Inc. All rights reserved.
//
// 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;
import "google/protobuf/unittest.proto";
import "unittest_extension_chain_c.proto";
// The Root for this file should end up adding the local extension and merging
// in the extensions from C's Root (unittest will come via C's).
message ChainBMessage {
optional ChainCMessage c = 1;
}
extend TestAllExtensions {
optional int32 chain_b_extension = 10002;
}
// Protocol Buffers - Google's data interchange format
// Copyright 2016 Google Inc. All rights reserved.
//
// 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;
import "google/protobuf/unittest.proto";
// The Root for this file should end up adding the local extension and merging
// in the extensions from unittest.proto's Root.
message ChainCMessage {
optional int32 my_field = 1;
}
extend TestAllExtensions {
optional int32 chain_c_extension = 10003;
}
// Protocol Buffers - Google's data interchange format
// Copyright 2016 Google Inc. All rights reserved.
//
// 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;
import "google/protobuf/unittest.proto";
import "unittest_extension_chain_b.proto";
import "unittest_extension_chain_c.proto";
// The root should end up needing to merge B (C will be merged into B, so it
// doesn't need to be directly merged).
message ChainDMessage {
optional ChainBMessage b = 1;
optional ChainCMessage c = 2;
}
extend TestAllExtensions {
optional int32 chain_d_extension = 10004;
}
// Protocol Buffers - Google's data interchange format
// Copyright 2016 Google Inc. All rights reserved.
//
// 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;
import "google/protobuf/unittest.proto";
// The Root for this file should end up just merging in unittest's Root.
message ChainEMessage {
optional TestAllTypes my_field = 1;
}
// Protocol Buffers - Google's data interchange format
// Copyright 2016 Google Inc. All rights reserved.
//
// 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;
import "unittest_extension_chain_g.proto";
// The Root for this file should just be merging in the extensions from C's
// Root (because G doens't define anything itself).
// The generated source will also have to directly import C's .h file so it can
// compile the reference to C's Root class.
message ChainFMessage {
optional ChainGMessage g = 1;
}
// Protocol Buffers - Google's data interchange format
// Copyright 2016 Google Inc. All rights reserved.
//
// 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;
import "unittest_extension_chain_c.proto";
// The Root for this file should just be merging in the extensions from C's
// Root.
message ChainGMessage {
optional ChainCMessage c = 1;
}
......@@ -27,6 +27,9 @@
@implementation GPBAnyRoot
// No extensions in the file and no imports, so no need to generate
// +extensionRegistry.
@end
#pragma mark - GPBAnyRoot_FileDescriptor
......
......@@ -31,18 +31,8 @@
@implementation GPBApiRoot
+ (GPBExtensionRegistry*)extensionRegistry {
// This is called by +initialize so there is no need to worry
// about thread safety and initialization of registry.
static GPBExtensionRegistry* registry = nil;
if (!registry) {
GPBDebugCheckRuntimeVersion();
registry = [[GPBExtensionRegistry alloc] init];
[registry addExtensions:[GPBSourceContextRoot extensionRegistry]];
[registry addExtensions:[GPBTypeRoot extensionRegistry]];
}
return registry;
}
// No extensions in the file and none of the imports (direct or indirect)
// defined extensions, so no need to generate +extensionRegistry.
@end
......
......@@ -27,6 +27,9 @@
@implementation GPBDurationRoot
// No extensions in the file and no imports, so no need to generate
// +extensionRegistry.
@end
#pragma mark - GPBDurationRoot_FileDescriptor
......
......@@ -27,6 +27,9 @@
@implementation GPBEmptyRoot
// No extensions in the file and no imports, so no need to generate
// +extensionRegistry.
@end
#pragma mark - GPBEmptyRoot_FileDescriptor
......
......@@ -27,6 +27,9 @@
@implementation GPBFieldMaskRoot
// No extensions in the file and no imports, so no need to generate
// +extensionRegistry.
@end
#pragma mark - GPBFieldMaskRoot_FileDescriptor
......
......@@ -27,6 +27,9 @@
@implementation GPBSourceContextRoot
// No extensions in the file and no imports, so no need to generate
// +extensionRegistry.
@end
#pragma mark - GPBSourceContextRoot_FileDescriptor
......
......@@ -28,6 +28,9 @@
@implementation GPBStructRoot
// No extensions in the file and no imports, so no need to generate
// +extensionRegistry.
@end
#pragma mark - GPBStructRoot_FileDescriptor
......
......@@ -27,6 +27,9 @@
@implementation GPBTimestampRoot
// No extensions in the file and no imports, so no need to generate
// +extensionRegistry.
@end
#pragma mark - GPBTimestampRoot_FileDescriptor
......
......@@ -31,18 +31,8 @@
@implementation GPBTypeRoot
+ (GPBExtensionRegistry*)extensionRegistry {
// This is called by +initialize so there is no need to worry
// about thread safety and initialization of registry.
static GPBExtensionRegistry* registry = nil;
if (!registry) {
GPBDebugCheckRuntimeVersion();
registry = [[GPBExtensionRegistry alloc] init];
[registry addExtensions:[GPBAnyRoot extensionRegistry]];
[registry addExtensions:[GPBSourceContextRoot extensionRegistry]];
}
return registry;
}
// No extensions in the file and none of the imports (direct or indirect)
// defined extensions, so no need to generate +extensionRegistry.
@end
......
......@@ -27,6 +27,9 @@
@implementation GPBWrappersRoot
// No extensions in the file and no imports, so no need to generate
// +extensionRegistry.
@end
#pragma mark - GPBWrappersRoot_FileDescriptor
......
......@@ -45,6 +45,10 @@
namespace google {
namespace protobuf {
namespace compiler {
namespace objectivec {
namespace {
// This is also found in GPBBootstrap.h, and needs to be kept in sync. It
// is the version check done to ensure generated code works with the current
......@@ -53,8 +57,106 @@ const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30001;
const char* kHeaderExtension = ".pbobjc.h";
namespace compiler {
namespace objectivec {
// Checks if a message contains any extension definitions (on the message or
// a nested message under it).
bool MessageContainsExtensions(const Descriptor* message) {
if (message->extension_count() > 0) {
return true;
}
for (int i = 0; i < message->nested_type_count(); i++) {
if (MessageContainsExtensions(message->nested_type(i))) {
return true;
}
}
return false;
}
// Checks if the file contains any extensions definitions (at the root or
// nested under a message).
bool FileContainsExtensions(const FileDescriptor* file) {
if (file->extension_count() > 0) {
return true;
}
for (int i = 0; i < file->message_type_count(); i++) {
if (MessageContainsExtensions(file->message_type(i))) {
return true;
}
}
return false;
}
// Helper for CollectMinimalFileDepsContainingExtensionsWorker that marks all
// deps as visited and prunes them from the needed files list.
void PruneFileAndDepsMarkingAsVisited(
const FileDescriptor* file,
vector<const FileDescriptor*>* files,
set<const FileDescriptor*>* files_visited) {
vector<const FileDescriptor*>::iterator iter =
std::find(files->begin(), files->end(), file);
if (iter != files->end()) {
files->erase(iter);
}
files_visited->insert(file);
for (int i = 0; i < file->dependency_count(); i++) {
PruneFileAndDepsMarkingAsVisited(file->dependency(i), files, files_visited);
}
}
// Helper for CollectMinimalFileDepsContainingExtensions.
void CollectMinimalFileDepsContainingExtensionsWorker(
const FileDescriptor* file,
vector<const FileDescriptor*>* files,
set<const FileDescriptor*>* files_visited) {
if (files_visited->find(file) != files_visited->end()) {
return;
}
files_visited->insert(file);
if (FileContainsExtensions(file)) {
files->push_back(file);
for (int i = 0; i < file->dependency_count(); i++) {
const FileDescriptor* dep = file->dependency(i);
PruneFileAndDepsMarkingAsVisited(dep, files, files_visited);
}
} else {
for (int i = 0; i < file->dependency_count(); i++) {
const FileDescriptor* dep = file->dependency(i);
CollectMinimalFileDepsContainingExtensionsWorker(dep, files,
files_visited);
}
}
}
// Collect the deps of the given file that contain extensions. This can be used to
// create the chain of roots that need to be wired together.
//
// NOTE: If any changes are made to this and the supporting functions, you will
// need to manually validate what the generated code is for the test files:
// objectivec/Tests/unittest_extension_chain_*.proto
// There are comments about what the expected code should be line and limited
// testing objectivec/Tests/GPBUnittestProtos2.m around compilation (#imports
// specifically).
void CollectMinimalFileDepsContainingExtensions(
const FileDescriptor* file,
vector<const FileDescriptor*>* files) {
set<const FileDescriptor*> files_visited;
for (int i = 0; i < file->dependency_count(); i++) {
const FileDescriptor* dep = file->dependency(i);
CollectMinimalFileDepsContainingExtensionsWorker(dep, files,
&files_visited);
}
}
bool IsDirectDependency(const FileDescriptor* dep, const FileDescriptor* file) {
for (int i = 0; i < file->dependency_count(); i++) {
if (dep == file->dependency(i)) {
return true;
}
}
return false;
}
} // namespace
FileGenerator::FileGenerator(const FileDescriptor *file, const Options& options)
: file_(file),
......@@ -204,6 +306,9 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
// #import the runtime support.
PrintFileRuntimePreamble(printer, "GPBProtocolBuffers_RuntimeSupport.h");
vector<const FileDescriptor*> deps_with_extensions;
CollectMinimalFileDepsContainingExtensions(file_, &deps_with_extensions);
{
ImportWriter import_writer(
options_.generate_for_named_framework,
......@@ -227,6 +332,18 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
}
}
// If any indirect dependency provided extensions, it needs to be directly
// imported so it can get merged into the root's extensions registry.
// See the Note by CollectMinimalFileDepsContainingExtensions before
// changing this.
for (vector<const FileDescriptor *>::iterator iter =
deps_with_extensions.begin();
iter != deps_with_extensions.end(); ++iter) {
if (!IsDirectDependency(*iter, file_)) {
import_writer.AddFile(*iter, header_extension);
}
}
import_writer.Print(printer);
}
......@@ -263,29 +380,11 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
"@implementation $root_class_name$\n\n",
"root_class_name", root_class_name_);
// Generate the extension initialization structures for the top level and
// any nested messages.
ostringstream extensions_stringstream;
if (file_->extension_count() + file_->message_type_count() > 0) {
io::OstreamOutputStream extensions_outputstream(&extensions_stringstream);
io::Printer extensions_printer(&extensions_outputstream, '$');
for (vector<ExtensionGenerator *>::iterator iter =
extension_generators_.begin();
iter != extension_generators_.end(); ++iter) {
(*iter)->GenerateStaticVariablesInitialization(&extensions_printer);
}
for (vector<MessageGenerator *>::iterator iter =
message_generators_.begin();
iter != message_generators_.end(); ++iter) {
(*iter)->GenerateStaticVariablesInitialization(&extensions_printer);
}
extensions_stringstream.flush();
}
const bool file_contains_extensions = FileContainsExtensions(file_);
// If there were any extensions or this file has any dependencies, output
// a registry to override to create the file specific registry.
const string& extensions_str = extensions_stringstream.str();
if (extensions_str.length() > 0 || file_->dependency_count() > 0) {
if (file_contains_extensions || !deps_with_extensions.empty()) {
printer->Print(
"+ (GPBExtensionRegistry*)extensionRegistry {\n"
" // This is called by +initialize so there is no need to worry\n"
......@@ -298,11 +397,20 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
printer->Indent();
printer->Indent();
if (extensions_str.length() > 0) {
if (file_contains_extensions) {
printer->Print(
"static GPBExtensionDescription descriptions[] = {\n");
printer->Indent();
printer->Print(extensions_str.c_str());
for (vector<ExtensionGenerator *>::iterator iter =
extension_generators_.begin();
iter != extension_generators_.end(); ++iter) {
(*iter)->GenerateStaticVariablesInitialization(printer);
}
for (vector<MessageGenerator *>::iterator iter =
message_generators_.begin();
iter != message_generators_.end(); ++iter) {
(*iter)->GenerateStaticVariablesInitialization(printer);
}
printer->Outdent();
printer->Print(
"};\n"
......@@ -315,11 +423,21 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
"}\n");
}
for (int i = 0; i < file_->dependency_count(); i++) {
const string root_class_name(FileClassName(file_->dependency(i)));
if (deps_with_extensions.empty()) {
printer->Print(
"[registry addExtensions:[$dependency$ extensionRegistry]];\n",
"dependency", root_class_name);
"// None of the imports (direct or indirect) defined extensions, so no need to add\n"
"// them to this registry.\n");
} else {
printer->Print(
"// Merge in the imports (direct or indirect) that defined extensions.\n");
for (vector<const FileDescriptor *>::iterator iter =
deps_with_extensions.begin();
iter != deps_with_extensions.end(); ++iter) {
const string root_class_name(FileClassName((*iter)));
printer->Print(
"[registry addExtensions:[$dependency$ extensionRegistry]];\n",
"dependency", root_class_name);
}
}
printer->Outdent();
......@@ -328,11 +446,20 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
printer->Print(
" }\n"
" return registry;\n"
"}\n"
"\n");
"}\n");
} else {
if (file_->dependency_count() > 0) {
printer->Print(
"// No extensions in the file and none of the imports (direct or indirect)\n"
"// defined extensions, so no need to generate +extensionRegistry.\n");
} else {
printer->Print(
"// No extensions in the file and no imports, so no need to generate\n"
"// +extensionRegistry.\n");
}
}
printer->Print("@end\n\n");
printer->Print("\n@end\n\n");
// File descriptor only needed if there are messages to use it.
if (message_generators_.size() > 0) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment