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;