Handle a CustomOption or CustomFieldOption that contains at least one OptionField.
Change-Id: Ifa4721eaf2e0449c14bd7366b352dfc85e35e7f8
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_FieldName_target_with_ExtensionFieldName_Test.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_FieldName_target_with_ExtensionFieldName_Test.java
index b003706..66a0a9d 100644
--- a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_FieldName_target_with_ExtensionFieldName_Test.java
+++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_FieldName_target_with_ExtensionFieldName_Test.java
@@ -25,8 +25,11 @@
import com.google.eclipse.protobuf.protobuf.ComplexValue;
import com.google.eclipse.protobuf.protobuf.ComplexValueCurlyBracket;
import com.google.eclipse.protobuf.protobuf.ComplexValueField;
+import com.google.eclipse.protobuf.protobuf.CustomFieldOption;
+import com.google.eclipse.protobuf.protobuf.CustomOption;
import com.google.eclipse.protobuf.protobuf.ExtensionFieldName;
import com.google.eclipse.protobuf.protobuf.FieldName;
+import com.google.eclipse.protobuf.protobuf.MessageField;
import com.google.eclipse.protobuf.protobuf.Option;
import com.google.eclipse.protobuf.protobuf.SimpleValueField;
import com.google.eclipse.protobuf.protobuf.ValueField;
@@ -112,4 +115,130 @@
IScope scope = scopeProvider.getScope(s.getName(), FIELD_NAME__TARGET);
assertThat(descriptionsIn(scope), contain("s"));
}
+
+ // syntax = "proto2";
+ //
+ // import "google/protobuf/descriptor.proto";
+ //
+ // package google.proto.sample;
+ //
+ // message TypeA {
+ // optional TypeB fieldb = 1;
+ // }
+ //
+ // message TypeB {
+ // optional string foo = 2;
+ // }
+ //
+ // extend google.protobuf.FieldOptions {
+ // optional TypeA optiona = 15478479;
+ // }
+ //
+ // message ExampleMessage {
+ // optional string examplefield = 3 [(optiona).fieldb = {
+ // foo : "Hello World!"
+ // }];
+ // }
+ @Test public void should_provide_sources_for_type_b_field() {
+ MessageField messageField = xtext.find("examplefield", " =", MessageField.class);
+ CustomFieldOption customFieldOption = (CustomFieldOption) messageField.getFieldOptions().get(0);
+ ComplexValueCurlyBracket curlyBracket = (ComplexValueCurlyBracket) customFieldOption.getValue();
+ SimpleValueField simpleValueField = (SimpleValueField) curlyBracket.getFields().get(0);
+ IScope scope = scopeProvider.getScope(simpleValueField.getName(), FIELD_NAME__TARGET);
+ assertThat(descriptionsIn(scope), contain("foo"));
+ }
+
+ // syntax = "proto2";
+ //
+ // import "google/protobuf/descriptor.proto";
+ //
+ // package google.proto.sample;
+ //
+ // message TypeA {
+ // optional TypeB fieldb = 1;
+ // }
+ //
+ // message TypeB {
+ // optional TypeC fieldc = 2;
+ // }
+ //
+ // message TypeC {
+ // optional string foo = 3;
+ // }
+ //
+ // extend google.protobuf.FieldOptions {
+ // optional TypeA optiona = 15478479;
+ // }
+ //
+ // message ExampleMessage {
+ // optional string examplefield = 3 [(optiona).fieldb.fieldc = {
+ // foo : "Hello World!"
+ // }];
+ // }
+ @Test public void should_provide_sources_for_type_c_field() {
+ MessageField messageField = xtext.find("examplefield", " =", MessageField.class);
+ CustomFieldOption fieldOption = (CustomFieldOption) messageField.getFieldOptions().get(0);
+ ComplexValueCurlyBracket complexValue = (ComplexValueCurlyBracket) fieldOption.getValue();
+ SimpleValueField valueField = (SimpleValueField) complexValue.getFields().get(0);
+ IScope scope = scopeProvider.getScope(valueField.getName(), FIELD_NAME__TARGET);
+ assertThat(descriptionsIn(scope), contain("foo"));
+ }
+
+ // syntax = "proto2";
+ //
+ // import "google/protobuf/descriptor.proto";
+ //
+ // package google.proto.sample;
+ //
+ // option (optionx).fieldy = { foo : "Hello World!" };
+ //
+ // message TypeX {
+ // optional TypeY fieldy = 1;
+ // }
+ //
+ // message TypeY {
+ // optional string foo = 2;
+ // }
+ //
+ // extend google.protobuf.FieldOptions {
+ // optional TypeX optionx = 15478479;
+ // }
+ @Test public void should_provide_sources_for_type_y_field() {
+ CustomOption customOption = xtext.find("optionx", ")", CustomOption.class);
+ ComplexValueCurlyBracket complexValue = (ComplexValueCurlyBracket) customOption.getValue();
+ SimpleValueField simpleValueField = (SimpleValueField) complexValue.getFields().get(0);
+ IScope scope = scopeProvider.getScope(simpleValueField.getName(), FIELD_NAME__TARGET);
+ assertThat(descriptionsIn(scope), contain("foo"));
+ }
+
+ // syntax = "proto2";
+ //
+ // import "google/protobuf/descriptor.proto";
+ //
+ // package google.proto.sample;
+ //
+ // option (optionx).fieldy.fieldz = { foo : "Hello World!" };
+ //
+ // message TypeX {
+ // optional TypeY fieldy = 1;
+ // }
+ //
+ // message TypeY {
+ // optional TypeZ fieldz = 2;
+ // }
+ //
+ // message TypeZ {
+ // optional string foo = 3;
+ // }
+ //
+ // extend google.protobuf.FieldOptions {
+ // optional TypeX optionx = 15478479;
+ // }
+ @Test public void should_provide_sources_for_type_z_field() {
+ CustomOption customOption = xtext.find("optionx", ")", CustomOption.class);
+ ComplexValueCurlyBracket complexValue = (ComplexValueCurlyBracket) customOption.getValue();
+ SimpleValueField valueField = (SimpleValueField) complexValue.getFields().get(0);
+ IScope scope = scopeProvider.getScope(valueField.getName(), FIELD_NAME__TARGET);
+ assertThat(descriptionsIn(scope), contain("foo"));
+ }
}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java
index c69fa05..10a1d1d 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java
@@ -262,16 +262,51 @@
EObject complexValue = valueField.eContainer();
if (complexValue instanceof ComplexValue) {
EObject unknownOption = complexValue.eContainer();
+
+ // Example CustomFieldOption with ComplexValue "{ opt1: 123}".
+ //
+ // optional int32 b = 1 [(foo_options) = {
+ // opt2: {
+ // opt1: 123
+ // }
+ // }];
+ //
+ // Handle a ComplexValue nested in a ComplexValueField.
if (unknownOption instanceof ComplexValueField) {
indexedElement = ((ComplexValueField) unknownOption).getName().getTarget();
}
+ if (indexedElement instanceof MessageField) {
+ return createNormalizedScopeForIndexedElement(indexedElement, reference);
+ }
+
+ // Example CustomOption with OptionField "example_option_field".
+ //
+ // option (foo_options).example_option_field = { opt1: 123 };
+ //
+ // Handle a CustomOption or CustomFieldOption that contains at least one OptionField.
+ EList<OptionField> optionFields = null;
+ if (unknownOption instanceof CustomOption) {
+ optionFields = ((CustomOption) unknownOption).getFields();
+ }
+ if (unknownOption instanceof CustomFieldOption) {
+ optionFields = ((CustomFieldOption) unknownOption).getFields();
+ }
+ if (optionFields != null && !optionFields.isEmpty()) {
+ OptionField lastOptionField = optionFields.get(optionFields.size() - 1);
+ indexedElement = lastOptionField.getTarget();
+ }
+ if (indexedElement instanceof MessageField) {
+ return createNormalizedScopeForIndexedElement(indexedElement, reference);
+ }
+
+ // Handle a NativeFieldOption, CustomFieldOption, NativeOption, or CustomOption.
if (unknownOption instanceof NativeFieldOption) {
NativeFieldOption nativeFieldOption = (NativeFieldOption) unknownOption;
optionSource = nativeFieldOption.getSource();
}
if (unknownOption instanceof CustomFieldOption) {
- CustomFieldOption customFieldOption = (CustomFieldOption) unknownOption;
- optionSource = customFieldOption.getSource();
+ CustomFieldOption option = (CustomFieldOption) unknownOption;
+ optionSource = option.getSource();
}
if (unknownOption instanceof NativeOption) {
NativeOption option = (NativeOption) unknownOption;