Include elements of oneofs in custom option scopes. This prevents usages of such options being flagged as errors and enables autocompletion of them. Change-Id: I80cbd7cfb6f99066f80626b831a6a23dec4b3e4b Signed-off-by: John Glassmyer <jogl@google.com>
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_OptionField_target_with_MessageOptionField_Test.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_OptionField_target_with_MessageOptionField_Test.java index 7b8b51e..f46338f 100644 --- a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_OptionField_target_with_MessageOptionField_Test.java +++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_OptionField_target_with_MessageOptionField_Test.java
@@ -15,6 +15,7 @@ import static com.google.eclipse.protobuf.junit.core.SearchOption.IGNORE_CASE; import static com.google.eclipse.protobuf.junit.core.XtextRule.overrideRuntimeModuleWith; import static com.google.eclipse.protobuf.junit.matchers.ContainAllFieldsInMessage.containAllFieldsIn; +import static com.google.eclipse.protobuf.junit.matchers.ContainAllNames.containAll; import org.eclipse.emf.ecore.EReference; import org.eclipse.xtext.scoping.IScope; @@ -182,4 +183,32 @@ Group groupMessage = xtext.find("Type", " =", Group.class); assertThat(descriptionsIn(scope), containAllFieldsIn(groupMessage)); } + + // syntax = "proto2"; + // + // package com.google.proto; + // + // import 'google/protobuf/descriptor.proto'; + // + // message Type { + // bool foo = 1; + // oneof choose_one { + // bool bar = 2; + // bool baz = 3; + // } + // } + // + // extend google.protobuf.FieldOptions { + // optional Type type = 1000; + // } + // + // message Person { + // optional bool active = 1 [(type).bar = true]; + // } + @Test public void should_provide_field_option_from_oneof() { + CustomFieldOption option = xtext.find("type", ")", CustomFieldOption.class); + MessageOptionField codeOptionField = (MessageOptionField) option.getFields().get(0); + IScope scope = scopeProvider.scope_OptionField_target(codeOptionField, reference); + assertThat(descriptionsIn(scope), containAll("foo", "bar", "baz")); + } }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/MessageFieldFinderStrategy.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/MessageFieldFinderStrategy.java index 7329bfb..f54118a 100644 --- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/MessageFieldFinderStrategy.java +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/MessageFieldFinderStrategy.java
@@ -12,7 +12,9 @@ import static com.google.common.collect.Sets.newHashSet; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Set; import org.eclipse.emf.ecore.EObject; @@ -21,11 +23,10 @@ import com.google.eclipse.protobuf.model.util.MessageFields; import com.google.eclipse.protobuf.model.util.Options; import com.google.eclipse.protobuf.protobuf.Group; -import com.google.eclipse.protobuf.protobuf.GroupElement; import com.google.eclipse.protobuf.protobuf.IndexedElement; import com.google.eclipse.protobuf.protobuf.Message; -import com.google.eclipse.protobuf.protobuf.MessageElement; import com.google.eclipse.protobuf.protobuf.MessageField; +import com.google.eclipse.protobuf.protobuf.OneOf; import com.google.inject.Inject; /** @@ -36,27 +37,44 @@ @Inject private Options options; @Override public Collection<IEObjectDescription> findOptionFields(IndexedElement reference) { - Set<IEObjectDescription> descriptions = newHashSet(); + Collection<? extends EObject> elements; if (reference instanceof MessageField) { Message fieldType = messageFields.messageTypeOf((MessageField) reference); - for (MessageElement element : fieldType.getElements()) { - IEObjectDescription d = describe(element); - if (d != null) { - descriptions.add(d); - } + if (fieldType != null) { + elements = fieldType.getElements(); + } else { + elements = Collections.emptySet(); } + } else if (reference instanceof Group) { + elements = ((Group) reference).getElements(); + } else { + elements = Collections.emptySet(); } - if (reference instanceof Group) { - for (GroupElement element : ((Group) reference).getElements()) { - IEObjectDescription d = describe(element); - if (d != null) { - descriptions.add(d); - } + + Set<IEObjectDescription> descriptions = newHashSet(); + Collection<EObject> expandedElements = expandOneOfs(elements); + for (EObject element : expandedElements) { + IEObjectDescription d = describe(element); + if (d != null) { + descriptions.add(d); } } return descriptions; } + private Collection<EObject> expandOneOfs(Collection<? extends EObject> elements) { + Collection<EObject> expandedElements = new ArrayList<>(elements.size()); + for (EObject element : elements) { + if (element instanceof OneOf) { + expandedElements.addAll(((OneOf) element).getElements()); + } + else { + expandedElements.add(element); + } + } + return expandedElements; + } + private IEObjectDescription describe(EObject e) { if (!(e instanceof IndexedElement)) { return null;