static ImmutableList<Field> retainAll( Schema schema, MarkSet markSet, ProtoType enclosingType, Collection<Field> fields) { ImmutableList.Builder<Field> result = ImmutableList.builder(); for (Field field : fields) { Field retainedField = field.retainAll(schema, markSet); if (retainedField != null && markSet.contains(ProtoMember.get(enclosingType, field.name()))) { result.add(retainedField); } } return result.build(); }
@Override Type retainAll(Schema schema, MarkSet markSet) { // If this type is not retained, prune it. if (!markSet.contains(protoType)) return null; ImmutableList.Builder<EnumConstant> retainedConstants = ImmutableList.builder(); for (EnumConstant constant : constants) { if (markSet.contains(ProtoMember.get(protoType, constant.name()))) { retainedConstants.add(constant.retainAll(schema, markSet)); } } EnumType result = new EnumType(protoType, location, documentation, name, retainedConstants.build(), options.retainAll(schema, markSet)); result.allowAlias = allowAlias; return result; }
Service retainAll(Schema schema, MarkSet markSet) { // If this service is not retained, prune it. if (!markSet.contains(protoType)) { return null; } ImmutableList.Builder<Rpc> retainedRpcs = ImmutableList.builder(); for (Rpc rpc : rpcs) { Rpc retainedRpc = rpc.retainAll(schema, markSet); if (retainedRpc != null && markSet.contains(ProtoMember.get(protoType, rpc.name()))) { retainedRpcs.add(retainedRpc); } } return new Service(protoType, location, documentation, name, retainedRpcs.build(), options.retainAll(schema, markSet)); }
private void markRoots(Service service) { ProtoType protoType = service.type(); if (identifierSet.includes(protoType)) { marks.root(protoType); queue.add(protoType); } else { for (Rpc rpc : service.rpcs()) { markRoots(ProtoMember.get(protoType, rpc.name())); } } }
private void markRoots(Type type) { ProtoType protoType = type.type(); if (identifierSet.includes(protoType)) { marks.root(protoType); queue.add(protoType); } else { if (type instanceof MessageType) { for (Field field : ((MessageType) type).fieldsAndOneOfFields()) { markRoots(ProtoMember.get(protoType, field.name())); } } else if (type instanceof EnumType) { for (EnumConstant enumConstant : ((EnumType) type).constants()) { markRoots(ProtoMember.get(protoType, enumConstant.name())); } } else { throw new AssertionError(); } } for (Type nested : type.nestedTypes()) { markRoots(nested); } }
private void markField(ProtoType declaringType, Field field) { if (marks.contains(ProtoMember.get(declaringType, field.name()))) { markOptions(field.options()); mark(field.type()); } }
@Test public void fieldOptions() throws Exception { Schema schema = new RepoBuilder() .add("message.proto", "" + "import \"google/protobuf/descriptor.proto\";\n" + "message Message {\n" + " optional int32 a = 1;\n" + " optional int32 b = 2 [color=red, deprecated=true, packed=true];\n" + "}\n" + "extend google.protobuf.FieldOptions {\n" + " optional string color = 60001;\n" + "}\n") .schema(); MessageType message = (MessageType) schema.getType("Message"); Options aOptions = message.field("a").options(); assertThat(aOptions.get(ProtoMember.get(FIELD_OPTIONS, "color"))).isNull(); assertThat(aOptions.get(ProtoMember.get(FIELD_OPTIONS, "deprecated"))).isNull(); assertThat(aOptions.get(ProtoMember.get(FIELD_OPTIONS, "packed"))).isNull(); Options bOptions = message.field("b").options(); assertThat(bOptions.get(ProtoMember.get(FIELD_OPTIONS, "color"))).isEqualTo("red"); assertThat(bOptions.get(ProtoMember.get(FIELD_OPTIONS, "deprecated"))).isEqualTo("true"); assertThat(bOptions.get(ProtoMember.get(FIELD_OPTIONS, "packed"))).isEqualTo("true"); }
private void markRpc(ProtoType declaringType, Rpc rpc) { if (marks.contains(ProtoMember.get(declaringType, rpc.name()))) { markOptions(rpc.options()); mark(rpc.requestType()); mark(rpc.responseType()); } } }
private Policy policy(IdentifierSet set, String identifier) { if (identifier.contains("#")) { ProtoMember protoMember = ProtoMember.get(identifier); if (set.includes(protoMember)) return Policy.INCLUDED; if (set.excludes(protoMember)) return Policy.EXCLUDED; return Policy.UNSPECIFIED; } else { ProtoType protoType = ProtoType.get(identifier); if (set.includes(protoType)) return Policy.INCLUDED; if (set.excludes(protoType)) return Policy.EXCLUDED; return Policy.UNSPECIFIED; } }
private void markEnum(EnumType wireEnum) { markOptions(wireEnum.options()); if (marks.containsAllMembers(wireEnum.type())) { for (EnumConstant constant : wireEnum.constants()) { if (marks.contains(ProtoMember.get(wireEnum.type(), constant.name()))) { markOptions(constant.options()); } } } }
@Test public void structuredAndUnstructuredOptions() throws Exception { // From https://developers.google.com/protocol-buffers/docs/proto#options Schema schema = new RepoBuilder() .add("foo.proto", "" + "import \"google/protobuf/descriptor.proto\";\n" + "message FooOptions {\n" + " optional int32 opt1 = 1;\n" + " optional string opt2 = 2;\n" + "}\n" + "\n" + "extend google.protobuf.FieldOptions {\n" + " optional FooOptions foo_options = 1234;\n" + "}\n" + "\n" + "message Bar {\n" + " optional int32 a = 1 [(foo_options).opt1 = 123, (foo_options).opt2 = \"baz\"];\n" + " optional int32 b = 2 [(foo_options) = { opt1: 456 opt2: \"quux\" }];\n" + "}\n") .schema(); ProtoMember fooOptions = ProtoMember.get(Options.FIELD_OPTIONS, "foo_options"); ProtoMember opt1 = ProtoMember.get(ProtoType.get("FooOptions"), "opt1"); ProtoMember opt2 = ProtoMember.get(ProtoType.get("FooOptions"), "opt2"); MessageType bar = (MessageType) schema.getType("Bar"); assertThat(bar.field("a").options().map()).isEqualTo(ImmutableMap.of( fooOptions, ImmutableMap.of(opt1, "123", opt2, "baz"))); assertThat(bar.field("b").options().map()).isEqualTo(ImmutableMap.of( fooOptions, ImmutableMap.of(opt1, "456", opt2, "quux"))); }
@Test public void retainMap() throws Exception { Schema schema = new RepoBuilder() .add("service.proto", "" + "message MessageA {\n" + " map<string, MessageB> maps = 1;\n" + " message MessageB {\n" + " }\n" + "}\n") .schema(); Schema pruned = schema.prune(new IdentifierSet.Builder() .include("MessageA") .build()); assertThat(pruned.getType("MessageA")).isNotNull(); assertThat(pruned.getField(ProtoMember.get("MessageA#maps"))).isNotNull(); }
@Test public void excludedFieldPrunesNestedOption() throws Exception { Schema schema = new RepoBuilder() .add("service.proto", "" + "import \"google/protobuf/descriptor.proto\";\n" + "message SomeFieldOptions {\n" + " optional string a = 1;\n" + " optional string b = 2;\n" + "}\n" + "extend google.protobuf.FieldOptions {\n" + " optional SomeFieldOptions some_field_options = 22001;\n" + "}\n" + "message Message {\n" + " optional string f = 1 [some_field_options = { a: \"a\", b: \"b\" }];\n" + "}\n") .schema(); Schema pruned = schema.prune(new IdentifierSet.Builder() .exclude("SomeFieldOptions#b") .build()); Field field = ((MessageType) pruned.getType("Message")).field("f"); Map<?, ?> map = (Map<?, ?>) field.options().get( ProtoMember.get(FIELD_OPTIONS, "some_field_options")); Map.Entry<?, ?> onlyOption = getOnlyElement(map.entrySet()); assertThat(((ProtoMember) onlyOption.getKey()).member()).isEqualTo("a"); assertThat(onlyOption.getValue()).isEqualTo("a"); }
@Test public void trackingUnusedIncludesPrecedence() throws Exception { IdentifierSet set = new IdentifierSet.Builder() .include("a.*") .include("a.IncludedType") .build(); set.includes(ProtoMember.get("a.IncludedType#member")); assertThat(set.unusedIncludes()).containsExactly("a.IncludedType"); }
@Test public void excludeRepeatedOptions() throws Exception { Schema schema = new RepoBuilder() .add("service.proto", "" + "import \"google/protobuf/descriptor.proto\";\n" + "extend google.protobuf.MessageOptions {\n" + " repeated string a = 22001;\n" + " repeated string b = 22002;\n" + "}\n" + "message Message {\n" + " option (a) = \"a1\";\n" + " option (a) = \"a2\";\n" + " option (b) = \"b1\";\n" + " option (b) = \"b2\";\n" + " optional string f = 1;\n" + "}\n") .schema(); Schema pruned = schema.prune(new IdentifierSet.Builder() .exclude("google.protobuf.MessageOptions#a") .build()); MessageType message = (MessageType) pruned.getType("Message"); assertThat(message.options().get(ProtoMember.get(MESSAGE_OPTIONS, "a"))).isNull(); assertThat(message.options().get(ProtoMember.get(MESSAGE_OPTIONS, "b"))) .isEqualTo(ImmutableList.of("b1", "b2")); }
@Test public void trackingUnusedExcludesPrecedence() throws Exception { IdentifierSet set = new IdentifierSet.Builder() .exclude("a.*") .exclude("a.IncludedType") .build(); set.includes(ProtoMember.get("a.IncludedType#member")); assertThat(set.unusedExcludes()).containsExactly("a.IncludedType"); }
@Test public void excludedFieldPrunesTopLevelOption() throws Exception { Schema schema = new RepoBuilder() .add("service.proto", "" + "import \"google/protobuf/descriptor.proto\";\n" + "extend google.protobuf.FieldOptions {\n" + " optional string a = 22001;\n" + " optional string b = 22002;\n" + "}\n" + "message Message {\n" + " optional string f = 1 [a = \"a\", b = \"b\"];\n" + "}\n") .schema(); Schema pruned = schema.prune(new IdentifierSet.Builder() .exclude("google.protobuf.FieldOptions#b") .build()); Field field = ((MessageType) pruned.getType("Message")).field("f"); assertThat(field.options().get(ProtoMember.get(FIELD_OPTIONS, "a"))).isEqualTo("a"); assertThat(field.options().get(ProtoMember.get(FIELD_OPTIONS, "b"))).isNull(); }
@Test public void excludeMap() throws Exception { Schema schema = new RepoBuilder() .add("service.proto", "" + "message MessageA {\n" + " map<string, MessageB> maps = 1;\n" + " message MessageB {\n" + " }\n" + "}\n") .schema(); Schema pruned = schema.prune(new IdentifierSet.Builder() .include("MessageA") .exclude("MessageA#maps") .build()); assertThat(pruned.getType("MessageA")).isNotNull(); assertThat(pruned.getField(ProtoMember.get("MessageA#maps"))).isNull(); }
@Test public void trackingUnusedExcludes() throws Exception { IdentifierSet set = new IdentifierSet.Builder() .exclude("a.*") .exclude("b.ExcludedType") .exclude("c.ExcludedMember#member") .build(); assertThat(set.unusedExcludes()).containsExactly( "a.*", "b.ExcludedType", "c.ExcludedMember#member"); set.includes(ProtoType.get("a.*")); assertThat(set.unusedExcludes()).containsExactly( "b.ExcludedType", "c.ExcludedMember#member"); set.includes(ProtoType.get("b.ExcludedType")); assertThat(set.unusedExcludes()).containsExactly( "c.ExcludedMember#member"); set.includes(ProtoMember.get("c.ExcludedMember#member")); assertThat(set.unusedExcludes()).isEmpty(); }
@Test public void trackingUnusedIncludes() throws Exception { IdentifierSet set = new IdentifierSet.Builder() .include("a.*") .include("b.IncludedType") .include("c.IncludedMember#member") .build(); assertThat(set.unusedIncludes()).containsExactly( "a.*", "b.IncludedType", "c.IncludedMember#member"); set.includes(ProtoType.get("a.*")); assertThat(set.unusedIncludes()).containsExactly( "b.IncludedType", "c.IncludedMember#member"); set.includes(ProtoType.get("b.IncludedType")); assertThat(set.unusedIncludes()).containsExactly( "c.IncludedMember#member"); set.includes(ProtoMember.get("c.IncludedMember#member")); assertThat(set.unusedIncludes()).isEmpty(); }