In progress: [Issue 155] Editor does not support complex custom options.
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_SimplePropertyRef_property_Test.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_MessagePropertyRef_messageProperty_Test.java
similarity index 79%
rename from com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_SimplePropertyRef_property_Test.java
rename to com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_MessagePropertyRef_messageProperty_Test.java
index 13bbbc5..0eb89a7 100644
--- a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_SimplePropertyRef_property_Test.java
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_MessagePropertyRef_messageProperty_Test.java
@@ -23,11 +23,11 @@
 import org.junit.*;
 
 /**
- * Tests for <code>{@link ProtobufScopeProvider#scope_SimplePropertyRef_property(SimplePropertyRef, EReference)}</code>
+ * Tests for <code>{@link ProtobufScopeProvider#scope_MessagePropertyRef_messageProperty(MessagePropertyRef, EReference)}</code>.
  * 
  * @author alruiz@google.com (Alex Ruiz)
  */
-public class ProtobufScopeProvider_scope_SimplePropertyRef_property_Test {
+public class ProtobufScopeProvider_scope_MessagePropertyRef_messageProperty_Test {
 
   private static EReference reference;
   
@@ -46,7 +46,7 @@
   // import 'google/protobuf/descriptor.proto';
   //  
   // message Type {
-  //   optional int32 code = 1;
+  //   optional double code = 1;
   //   optional string name = 2;
   // }
   //  
@@ -57,7 +57,8 @@
   // option (type).code = 68;
   @Test public void should_provide_Property_fields_for_custom_option_field() {
     CustomOption option = xtext.find("type", ")", CustomOption.class);
-    IScope scope = provider.scope_SimplePropertyRef_property(option.getPropertyField(), reference);
+    MessagePropertyRef optionField = (MessagePropertyRef) option.getOptionFields().get(0);
+    IScope scope = provider.scope_MessagePropertyRef_messageProperty(optionField, reference);
     Message typeMessage = xtext.find("Type", " {", Message.class);
     assertThat(descriptionsIn(scope), containAllPropertiesIn(typeMessage));
   }
@@ -65,7 +66,7 @@
   // import 'google/protobuf/descriptor.proto';
   //  
   // message Type {
-  //   optional int32 code = 1;
+  //   optional double code = 1;
   //   optional string name = 2;
   // }
   //
@@ -78,7 +79,8 @@
   // }
   @Test public void should_provide_Property_fields_for_custom_field_option_field() {
     CustomFieldOption option = xtext.find("type", ")", CustomFieldOption.class);
-    IScope scope = provider.scope_SimplePropertyRef_property(option.getPropertyField(), reference);
+    MessagePropertyRef optionField = (MessagePropertyRef) option.getOptionFields().get(0);
+    IScope scope = provider.scope_MessagePropertyRef_messageProperty(optionField, reference);
     Message typeMessage = xtext.find("Type", " {", Message.class);
     assertThat(descriptionsIn(scope), containAllPropertiesIn(typeMessage));
   }
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/model/util/ModelFinder_extensionsFrom_Test.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/model/util/ModelFinder_extensionsFrom_Test.java
new file mode 100644
index 0000000..a853ce7
--- /dev/null
+++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/model/util/ModelFinder_extensionsFrom_Test.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.model.util;
+
+import static com.google.eclipse.protobuf.junit.core.Setups.unitTestSetup;
+import static com.google.eclipse.protobuf.junit.core.XtextRule.createWith;
+import static org.junit.Assert.assertSame;
+
+import com.google.eclipse.protobuf.junit.core.XtextRule;
+import com.google.eclipse.protobuf.protobuf.*;
+
+import org.junit.*;
+
+import java.util.*;
+
+/**
+ * Tests for <code>{@link ModelFinder#extensionsOf(Message)}</code>.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class ModelFinder_extensionsFrom_Test {
+
+  @Rule public XtextRule xtext = createWith(unitTestSetup());
+
+  private ModelFinder finder;
+
+  @Before public void setUp() {
+    finder = xtext.getInstanceOf(ModelFinder.class);
+  }
+
+  // message Person {
+  //   optional string name = 1;
+  // }
+  //
+  // extend Person {}
+  @Test public void should_return_extensions_of_message() {
+    Message m = xtext.find("Person", " {", Message.class);
+    List<ExtendMessage> extensions = new ArrayList<ExtendMessage>(finder.extensionsOf(m));
+    Message referred = extensions.get(0).getMessage().getType();
+    assertSame(m, referred);
+  }
+}
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/model/util/ModelFinder_messageFrom_Test.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/model/util/ModelFinder_messageFrom_Test.java
new file mode 100644
index 0000000..88abdd9
--- /dev/null
+++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/model/util/ModelFinder_messageFrom_Test.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.model.util;
+
+import static com.google.eclipse.protobuf.junit.core.Setups.unitTestSetup;
+import static com.google.eclipse.protobuf.junit.core.XtextRule.createWith;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import com.google.eclipse.protobuf.junit.core.XtextRule;
+import com.google.eclipse.protobuf.protobuf.*;
+
+import org.junit.*;
+
+/**
+ * Tests for <code>{@link ModelFinder#messageFrom(ExtendMessage)}</code>.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class ModelFinder_messageFrom_Test {
+
+  @Rule public XtextRule xtext = createWith(unitTestSetup());
+
+  private ModelFinder finder;
+
+  @Before public void setUp() {
+    finder = xtext.getInstanceOf(ModelFinder.class);
+  }
+
+  // message Person {
+  //   optional string name = 1;
+  // }
+  //
+  // extend Person {}
+  @Test public void should_return_message_from_extension() {
+    ExtendMessage extension = xtext.find("Person", " {}", ExtendMessage.class);
+    Message message = finder.messageFrom(extension);
+    assertThat(message.getName(), equalTo("Person"));
+  }
+  
+  @Test public void should_return_null_if_extension_is_not_referring_to_message() {
+    ExtendMessage extension = mock(ExtendMessage.class);
+    when(extension.getMessage()).thenReturn(null);
+    assertNull(finder.messageFrom(extension));
+  }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/contentassist/ProtobufProposalProvider.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/contentassist/ProtobufProposalProvider.java
index ef89dcf..f15b361 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/contentassist/ProtobufProposalProvider.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/contentassist/ProtobufProposalProvider.java
@@ -405,7 +405,7 @@
       ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
   }
   
-  @Override public void completeSimplePropertyRef_Property(EObject model, Assignment assignment,
+  @Override public void completeMessagePropertyRef_MessageProperty(EObject model, Assignment assignment,
       ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
   }
   
@@ -444,20 +444,35 @@
     acceptor.accept(proposal);
   }
   
-  @Override public void completeCustomOption_PropertyField(EObject model, Assignment assignment,
+  @Override public void completeCustomOption_OptionFields(EObject model, Assignment assignment,
       ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
-    if (!(model instanceof CustomOption)) return;
-    Property property = options.propertyFrom((CustomOption) model);
-    proposeAndAcceptOptionFields(property, context, acceptor);
+    super.completeCustomOption_OptionFields(model, assignment, context, acceptor);
+  }
+
+  @Override public void completeCustomFieldOption_OptionFields(EObject model, Assignment assignment,
+      ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
+    super.completeCustomFieldOption_OptionFields(model, assignment, context, acceptor);
   }
   
-  @Override public void completeCustomFieldOption_PropertyField(EObject model, Assignment assignment,
-      ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
-    if (!(model instanceof CustomFieldOption)) return;
-    Property property = fieldOptions.propertyFrom((CustomFieldOption) model);
-    proposeAndAcceptOptionFields(property, context, acceptor);
+  @Override public void complete_MessagePropertyRef(EObject model, RuleCall ruleCall, ContentAssistContext context,
+      ICompletionProposalAcceptor acceptor) {  
+    super.complete_MessagePropertyRef(model, ruleCall, context, acceptor);
   }
   
+//  @Override public void completeCustomOption_PropertyField(EObject model, Assignment assignment,
+//      ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
+//    if (!(model instanceof CustomOption)) return;
+//    Property property = options.propertyFrom((CustomOption) model);
+//    proposeAndAcceptOptionFields(property, context, acceptor);
+//  }
+//  
+//  @Override public void completeCustomFieldOption_PropertyField(EObject model, Assignment assignment,
+//      ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
+//    if (!(model instanceof CustomFieldOption)) return;
+//    Property property = fieldOptions.propertyFrom((CustomFieldOption) model);
+//    proposeAndAcceptOptionFields(property, context, acceptor);
+//  }
+  
   private void proposeAndAcceptOptionFields(Property property, ContentAssistContext context,
       ICompletionProposalAcceptor acceptor) {
     Message message = finder.messageTypeOf(property);
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/Protobuf.xtext b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/Protobuf.xtext
index e90bb84..1698f3f 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/Protobuf.xtext
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/Protobuf.xtext
@@ -200,8 +200,9 @@
   'option' property=PropertyRef '=' value=ValueRef ';';
 
 CustomOption:
-  'option' '(' property=PropertyRef ')'('.' propertyField = SimplePropertyRef)? '=' value=ValueRef ';';
-
+  'option' '(' property=PropertyRef ')'
+  ('.' optionFields+=OptionField ('.' optionFields+=OptionField)*)? '=' value=ValueRef ';';
+ 
 FieldOption:
   DefaultValueFieldOption | NativeFieldOption | CustomFieldOption;
 
@@ -212,10 +213,18 @@
   property=PropertyRef '=' value=ValueRef;
 
 CustomFieldOption:
-  '(' property=PropertyRef ')'('.' propertyField = SimplePropertyRef)? '=' value=ValueRef;
+  '(' property=PropertyRef ')'
+  ('.' optionFields+=OptionField ('.' optionFields+=OptionField)*)? '=' value=ValueRef;
 
 PropertyRef:
   property=[Property|QualifiedName];
 
-SimplePropertyRef:
-  property=[Property];  
\ No newline at end of file
+OptionField:
+  MessagePropertyRef | ExtendMessagePropertyRef;
+
+MessagePropertyRef:
+  messageProperty=[Property];  
+
+ExtendMessagePropertyRef:
+  '(' extendMessageProperty=[Property|QualifiedName] ')';  
+  
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/FieldOptions.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/FieldOptions.java
index 41d1365..2b6cac0 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/FieldOptions.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/FieldOptions.java
@@ -74,7 +74,8 @@
    * one cannot be found.
    */
   public Property fieldFrom(CustomFieldOption option) {
-    SimplePropertyRef ref = option.getPropertyField();
-    return (ref == null) ? null : ref.getProperty();
+    return null;
+    // SimplePropertyRef ref = option.getPropertyField();
+    // return (ref == null) ? null : ref.getProperty();
   }
 }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/ModelFinder.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/ModelFinder.java
index 3529d39..9fbb8f0 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/ModelFinder.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/ModelFinder.java
@@ -10,18 +10,19 @@
 
 import static java.util.Collections.unmodifiableList;
 import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents;
+import static org.eclipse.xtext.EcoreUtil2.getAllContentsOfType;
 
-import java.util.*;
+import com.google.eclipse.protobuf.protobuf.*;
+import com.google.eclipse.protobuf.protobuf.Enum;
+import com.google.eclipse.protobuf.protobuf.Package;
+import com.google.inject.Singleton;
 
 import org.eclipse.emf.common.util.TreeIterator;
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.ecore.resource.Resource;
 import org.eclipse.xtext.resource.XtextResource;
 
-import com.google.eclipse.protobuf.protobuf.*;
-import com.google.eclipse.protobuf.protobuf.Enum;
-import com.google.eclipse.protobuf.protobuf.Package;
-import com.google.inject.Singleton;
+import java.util.*;
 
 /**
  * Utility methods to find elements in a parser proto file.
@@ -32,6 +33,31 @@
 public class ModelFinder {
 
   /**
+   * Returns all the <strong>local</strong> extensions of the given message.
+   * @param m the given message.
+   * @return all the <strong>local</strong> extensions of the given message, or an empty collection if none is found.
+   */
+  public Collection<ExtendMessage> extensionsOf(Message m) {
+    Set<ExtendMessage> extensions = new HashSet<ExtendMessage>();
+    Protobuf root = rootOf(m);
+    for (ExtendMessage extension : getAllContentsOfType(root, ExtendMessage.class)) {
+      Message referred = messageFrom(extension);
+      if (m.equals(referred)) extensions.add(extension);
+    }
+    return extensions;
+  }
+  
+  /**
+   * Returns the message from the given extension.
+   * @param e the given extension.
+   * @return the message from the given extension, or {@code null} if the extension is not referring to a message.
+   */
+  public Message messageFrom(ExtendMessage e) {
+    MessageRef ref = e.getMessage();
+    return ref == null ? null : ref.getType();
+  }
+
+  /**
    * Returns the message type of the given property, only if the type of the given property is a message.
    * @param p the given property.
    * @return the message type of the given property or {@code null} if the type of the given property is not message.
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Options.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Options.java
index de6cd8f..afa0b5a 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Options.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Options.java
@@ -47,7 +47,8 @@
    * cannot be found.
    */
   public Property fieldFrom(CustomOption option) {
-    SimplePropertyRef ref = option.getPropertyField();
-    return (ref == null) ? null : ref.getProperty();
+    return null;
+    // SimplePropertyRef ref = option.getPropertyField();
+    // return (ref == null) ? null : ref.getProperty();
   }
 }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionDescriptions.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionDescriptions.java
deleted file mode 100644
index 58a67d2..0000000
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionDescriptions.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (c) 2011 Google Inc.
- *
- * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
- * Public License v1.0 which accompanies this distribution, and is available at
- *
- * http://www.eclipse.org/legal/epl-v10.html
- */
-package com.google.eclipse.protobuf.scoping;
-
-import static com.google.eclipse.protobuf.scoping.OptionType.typeOf;
-import static java.util.Collections.emptyList;
-import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents;
-import static org.eclipse.xtext.resource.EObjectDescription.create;
-
-import java.util.*;
-
-import org.eclipse.emf.common.util.TreeIterator;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.resource.*;
-import org.eclipse.xtext.naming.QualifiedName;
-import org.eclipse.xtext.resource.IEObjectDescription;
-
-import com.google.eclipse.protobuf.model.util.*;
-import com.google.eclipse.protobuf.protobuf.*;
-import com.google.eclipse.protobuf.protobuf.Package;
-import com.google.inject.Inject;
-
-/**
- * @author alruiz@google.com (Alex Ruiz)
- */
-class CustomOptionDescriptions {
-
-  @Inject private ModelFinder finder;
-  @Inject private Imports imports;
-  @Inject private LocalNamesProvider localNamesProvider;
-  @Inject private Packages packages;
-  @Inject private QualifiedNameDescriptions qualifiedNamesDescriptions;
-  @Inject private Resources resources;
-
-  public Collection <IEObjectDescription> properties(CustomOption option) {
-    return allProperties(option, typeOf(option));
-  }
-
-  public Collection <IEObjectDescription> properties(CustomFieldOption option) {
-    return allProperties(option, typeOf(option));
-  }
-
-  private Collection <IEObjectDescription> allProperties(EObject option, OptionType type) {
-    Set<IEObjectDescription> descriptions = new LinkedHashSet<IEObjectDescription>();
-    EObject current = option.eContainer();
-    while (current != null) {
-      descriptions.addAll(local(current, type));
-      current = current.eContainer();
-    }
-    Protobuf root = finder.rootOf(option);
-    descriptions.addAll(imported(root, type));
-    return descriptions;
-  }
-
-  private Collection <IEObjectDescription> local(EObject root, OptionType optionType) {
-    return local(root, optionType, 0);
-  }
-
-  private Collection <IEObjectDescription> local(EObject root, OptionType optionType, int level) {
-    if (optionType == null) return emptyList();
-    Set<IEObjectDescription> descriptions = new LinkedHashSet<IEObjectDescription>();
-    for (EObject element : root.eContents()) {
-      if (isExtendingOptionMessage(element, optionType)) {
-        ExtendMessage extend = (ExtendMessage) element;
-        for (MessageElement e : extend.getElements()) {
-          if (!(e instanceof Property)) continue;
-          Property p = (Property) e;
-          List<QualifiedName> names = localNamesProvider.namesOf(p);
-          int nameCount = names.size();
-          for (int i = level; i < nameCount; i++) {
-            descriptions.add(create(names.get(i), p));
-          }
-          descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(p));
-        }
-      }
-      if (element instanceof Message) {
-        descriptions.addAll(local(element, optionType, level + 1));
-      }
-    }
-    return descriptions;
-  }
-
-  private Collection<IEObjectDescription> imported(Protobuf root, OptionType optionType) {
-    List<Import> allImports = finder.importsIn(root);
-    if (allImports.isEmpty()) return emptyList();
-    ResourceSet resourceSet = root.eResource().getResourceSet();
-    return imported(allImports, finder.packageOf(root), resourceSet, optionType);
-  }
-
-  private Collection<IEObjectDescription> imported(List<Import> allImports, Package aPackage,
-      ResourceSet resourceSet, OptionType optionType) {
-    Set<IEObjectDescription> descriptions = new LinkedHashSet<IEObjectDescription>();
-    for (Import anImport : allImports) {
-      if (imports.isImportingDescriptor(anImport)) continue;
-      Resource importedResource = resources.importedResource(anImport, resourceSet);
-      Protobuf importedRoot = finder.rootOf(importedResource);
-      if (importedRoot != null) {
-        descriptions.addAll(publicImported(importedRoot, optionType));
-        if (arePackagesRelated(aPackage, importedRoot)) {
-          descriptions.addAll(local(importedRoot, optionType));
-          continue;
-        }
-      }
-      descriptions.addAll(local(importedResource, optionType));
-    }
-    return descriptions;
-  }
-
-  private <T extends Type> Collection<IEObjectDescription> publicImported(Protobuf root, OptionType optionType) {
-    List<Import> allImports = finder.publicImportsIn(root);
-    if (allImports.isEmpty()) return emptyList();
-    ResourceSet resourceSet = root.eResource().getResourceSet();
-    return imported(allImports, finder.packageOf(root), resourceSet, optionType);
-  }
-
-  private boolean arePackagesRelated(Package aPackage, EObject root) {
-    Package p = finder.packageOf(root);
-    return packages.areRelated(aPackage, p);
-  }
-
-  private Collection<IEObjectDescription> local(Resource resource, OptionType optionType) {
-    List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
-    TreeIterator<Object> contents = getAllContents(resource, true);
-    while (contents.hasNext()) {
-      Object next = contents.next();
-      if (!isExtendingOptionMessage((EObject) next, optionType)) continue;
-      ExtendMessage extend = (ExtendMessage) next;
-      for (MessageElement e : extend.getElements()) {
-        if (!(e instanceof Property)) continue;
-        Property p = (Property) e;
-        descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(p));
-        // TODO verify that call to 'importedNamesProvider.namesOf' is not necessary
-      }
-    }
-    return descriptions;
-  }
-
-  private boolean isExtendingOptionMessage(EObject o, OptionType optionType) {
-    if (!(o instanceof ExtendMessage)) return false;
-    Message message = messageFrom((ExtendMessage) o);
-    if (message == null) return false;
-    return optionType.messageName().equals(message.getName());
-  }
-
-  private Message messageFrom(ExtendMessage extend) {
-    MessageRef ref = extend.getMessage();
-    return ref == null ? null : ref.getType();
-  }
-
-  /*
-   * Scope for 'y' in:
-   * option Type (x).y = 0;
-   */
-  Collection <IEObjectDescription> fields(Property optionProperty) {
-    Message propertyType = finder.messageTypeOf(optionProperty);
-    if (propertyType == null) return emptyList();
-    Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
-    for (MessageElement e : propertyType.getElements()) {
-      if (!(e instanceof Property)) continue;
-      Property optionPropertyField = (Property) e;
-      descriptions.add(create(optionPropertyField.getName(), optionPropertyField));
-    }
-    return descriptions;
-  }
-}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionSearchDelegate.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionSearchDelegate.java
new file mode 100644
index 0000000..8f60b2a
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionSearchDelegate.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.scoping;
+
+import org.eclipse.xtext.resource.IEObjectDescription;
+
+import java.util.Collection;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class CustomOptionSearchDelegate extends ExtendMessageSearchDelegate {
+
+  @Override public Collection<IEObjectDescription> descriptions(Object target, Object criteria) {
+    OptionType optionType = optionTypeFrom(criteria);
+    return super.descriptions(target, optionType.messageName());
+  }
+
+  @Override public Collection<IEObjectDescription> descriptions(Object target, Object criteria, int level) {
+    OptionType optionType = optionTypeFrom(criteria);
+    return super.descriptions(target, optionType.messageName(), level);
+  }
+
+  private OptionType optionTypeFrom(Object criteria) {
+    if (!(criteria instanceof OptionType)) 
+      throw new IllegalArgumentException("Search criteria should be OptionType");
+    return (OptionType) criteria;
+  }
+}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ExtendMessageSearchDelegate.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ExtendMessageSearchDelegate.java
new file mode 100644
index 0000000..2473fd2
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ExtendMessageSearchDelegate.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.scoping;
+
+import static java.util.Collections.emptySet;
+import static org.eclipse.xtext.resource.EObjectDescription.create;
+
+import com.google.eclipse.protobuf.model.util.ModelFinder;
+import com.google.eclipse.protobuf.protobuf.*;
+import com.google.inject.Inject;
+
+import org.eclipse.xtext.naming.QualifiedName;
+import org.eclipse.xtext.resource.IEObjectDescription;
+
+import java.util.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class ExtendMessageSearchDelegate implements SearchDelegate {
+
+  @Inject private LocalNamesProvider localNamesProvider;
+  @Inject private ModelFinder modelFinder;
+  @Inject private QualifiedNameDescriptions qualifiedNamesDescriptions;
+
+  @Override public boolean continueSearchOneLevelHigher(Object target) {
+    return target instanceof Message;
+  }
+
+  @Override public Collection<IEObjectDescription> fromProtoDescriptor(Import anImport, Object criteria) {
+    return emptySet();
+  }
+
+  @Override public Collection<IEObjectDescription> descriptions(Object target, Object criteria) {
+    String messageName = messageNameFrom(criteria);
+    if (!isExtendingOptionMessage(target, messageName)) return emptySet();
+    Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+    ExtendMessage extend = (ExtendMessage) target;
+    for (MessageElement e : extend.getElements()) {
+      if (!(e instanceof Property)) continue;
+      Property p = (Property) e;
+      descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(p));
+    }
+    return descriptions;
+  }
+
+  @Override public Collection<IEObjectDescription> descriptions(Object target, Object criteria, int level) {
+    String messageName = messageNameFrom(criteria);
+    if (!isExtendingOptionMessage(target, messageName)) return emptySet();
+    Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+    ExtendMessage extend = (ExtendMessage) target;
+    for (MessageElement e : extend.getElements()) {
+      if (!(e instanceof Property)) continue;
+      Property p = (Property) e;
+      List<QualifiedName> names = localNamesProvider.namesOf(p);
+      int nameCount = names.size();
+      for (int i = level; i < nameCount; i++) {
+        descriptions.add(create(names.get(i), p));
+      }
+      descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(p));
+    }
+    return descriptions;
+  }
+
+  private String messageNameFrom(Object criteria) {
+    if (!(criteria instanceof String)) 
+      throw new IllegalArgumentException("Search criteria should be String");
+    return (String) criteria;
+  }
+
+  private boolean isExtendingOptionMessage(Object o, String messageName) {
+    if (!(o instanceof ExtendMessage)) return false;
+    Message message = modelFinder.messageFrom((ExtendMessage) o);
+    if (message == null) return false;
+    return messageName.equals(message.getName());
+  }
+}
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 1e050c7..a387f2f 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
@@ -8,19 +8,21 @@
  */
 package com.google.eclipse.protobuf.scoping;
 
-import static java.util.Collections.emptySet;
+import static com.google.eclipse.protobuf.scoping.OptionType.typeOf;
+import static java.util.Collections.*;
+import static org.eclipse.xtext.resource.EObjectDescription.create;
 
-import java.util.*;
+import com.google.eclipse.protobuf.model.util.*;
+import com.google.eclipse.protobuf.protobuf.*;
+import com.google.eclipse.protobuf.protobuf.Enum;
+import com.google.inject.*;
 
 import org.eclipse.emf.ecore.*;
 import org.eclipse.xtext.resource.IEObjectDescription;
 import org.eclipse.xtext.scoping.IScope;
 import org.eclipse.xtext.scoping.impl.*;
 
-import com.google.eclipse.protobuf.model.util.*;
-import com.google.eclipse.protobuf.protobuf.*;
-import com.google.eclipse.protobuf.protobuf.Enum;
-import com.google.inject.Inject;
+import java.util.*;
 
 /**
  * Custom scoping description.
@@ -33,21 +35,23 @@
 
   private static final boolean DO_NOT_IGNORE_CASE = false;
 
-  @Inject private CustomOptionDescriptions customOptionDescriptions;
+  @Inject private CustomOptionSearchDelegate customOptionSearchDelegate;
   @Inject private ProtoDescriptorProvider descriptorProvider;
   @Inject private FieldOptions fieldOptions;
-  @Inject private ModelFinder finder;
+  @Inject private ModelFinder modelFinder;
   @Inject private LiteralDescriptions literalDescriptions;
   @Inject private NativeOptionDescriptions nativeOptionDescriptions;
   @Inject private Options options;
-  @Inject private TypeDescriptions typeDescriptions;
+  @Inject private ScopeFinder scopeFinder;
+  @Inject private TypeSearchDelegate typeSearchDelegate;
+  @Inject private QualifiedNameDescriptions qualifiedNamesDescriptions;
 
   @SuppressWarnings("unused")
   public IScope scope_TypeRef_type(TypeRef typeRef, EReference reference) {
     EObject c = typeRef.eContainer();
     if (c instanceof Property) {
       Property property = (Property) c;
-      return createScope(typeDescriptions.types(property));
+      return createScope(scopeFinder.findScope(property, typeSearchDelegate, Type.class));
     }
     Set<IEObjectDescription> descriptions = emptySet();
     return createScope(descriptions);
@@ -55,8 +59,8 @@
 
   @SuppressWarnings("unused")
   public IScope scope_MessageRef_type(MessageRef messageRef, EReference reference) {
-    Protobuf root = finder.rootOf(messageRef);
-    return createScope(typeDescriptions.messages(root));
+    Protobuf root = modelFinder.rootOf(messageRef);
+    return createScope(scopeFinder.findScope(root, typeSearchDelegate, Message.class));
   }
 
   @SuppressWarnings("unused")
@@ -65,7 +69,7 @@
     Enum anEnum = null;
     if (c instanceof DefaultValueFieldOption) {
       EObject optionContainer = c.eContainer();
-      if (optionContainer instanceof Property) anEnum = finder.enumTypeOf((Property) optionContainer);
+      if (optionContainer instanceof Property) anEnum = modelFinder.enumTypeOf((Property) optionContainer);
     }
     if (c instanceof NativeOption) {
       ProtoDescriptor descriptor = descriptorProvider.primaryDescriptor();
@@ -88,7 +92,7 @@
       if (c == null) c = fieldOptions.propertyFrom(option);
     }
     if (c instanceof Property) {
-      anEnum = finder.enumTypeOf((Property) c);
+      anEnum = modelFinder.enumTypeOf((Property) c);
     }
     return createScope(literalDescriptions.literalsOf(anEnum));
   }
@@ -106,35 +110,132 @@
     }
     if (c instanceof CustomOption) {
       CustomOption option = (CustomOption) c;
-      return createScope(customOptionDescriptions.properties(option));
+      return createScope(scopeFinder.findScope(option, customOptionSearchDelegate, typeOf(option)));
     }
     if (c instanceof CustomFieldOption) {
       CustomFieldOption option = (CustomFieldOption) c;
-      return createScope(customOptionDescriptions.properties(option));
+      return createScope(scopeFinder.findScope(option, customOptionSearchDelegate, typeOf(option)));
     }
     Set<IEObjectDescription> descriptions = emptySet();
     return createScope(descriptions);
   }
   
   @SuppressWarnings("unused") 
-  public IScope scope_SimplePropertyRef_property(SimplePropertyRef propertyRef, EReference reference) {
+  public IScope scope_MessagePropertyRef_messageProperty(MessagePropertyRef propertyRef, EReference reference) {
     EObject c = propertyRef.eContainer();
     Property property = null;
     if (c instanceof CustomOption) {
-      CustomOption option = (CustomOption) c;
-      property = options.propertyFrom(option);
+      final CustomOption option = (CustomOption) c;
+      property = referencedProperty(propertyRef, option.getOptionFields(), new Provider<Property>() {
+        @Override public Property get() {
+          return options.propertyFrom(option);
+        }
+      });
     }
     if (c instanceof CustomFieldOption) {
-      CustomFieldOption option = (CustomFieldOption) c;
-      property = fieldOptions.propertyFrom(option);
+      final CustomFieldOption option = (CustomFieldOption) c;
+      property = referencedProperty(propertyRef, option.getOptionFields(), new Provider<Property>() {
+        @Override public Property get() {
+          return fieldOptions.propertyFrom(option);
+        }
+      });
     }
     if (property != null) {
-      return createScope(customOptionDescriptions.fields(property));
+      return createScope(fieldsInMessageContaining(property));
+    }
+    Set<IEObjectDescription> descriptions = emptySet();
+    return createScope(descriptions);
+  }
+  
+  private Property referencedProperty(MessagePropertyRef ref, List<OptionField> fields, Provider<Property> provider) {
+    OptionField previous = null;
+    boolean isFirstField = true;
+    for (OptionField field : fields) {
+      if (field == ref) return (isFirstField) ? provider.get() : propertyFrom(previous);
+      previous = field;
+      isFirstField = false;
+    }
+    return null;
+  }
+  
+  private Collection <IEObjectDescription> fieldsInMessageContaining(Property p) {
+    Message propertyType = modelFinder.messageTypeOf(p);
+    if (propertyType == null) return emptyList();
+    Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+    for (MessageElement e : propertyType.getElements()) {
+      if (!(e instanceof Property)) continue;
+      Property optionPropertyField = (Property) e;
+      descriptions.add(create(optionPropertyField.getName(), optionPropertyField));
+    }
+    return descriptions;
+  }
+
+  @SuppressWarnings("unused") 
+  public IScope scope_ExtendMessagePropertyRef_extendMessageProperty(ExtendMessagePropertyRef propertyRef, 
+      EReference reference) {
+    EObject c = propertyRef.eContainer();
+    Property property = null;
+    if (c instanceof CustomOption) {
+      final CustomOption option = (CustomOption) c;
+      property = referencedProperty(propertyRef, option.getOptionFields(), new Provider<Property>() {
+        @Override public Property get() {
+          return options.propertyFrom(option);
+        }
+      });
+    }
+    if (c instanceof CustomFieldOption) {
+      final CustomFieldOption option = (CustomFieldOption) c;
+      property = referencedProperty(propertyRef, option.getOptionFields(), new Provider<Property>() {
+        @Override public Property get() {
+          return fieldOptions.propertyFrom(option);
+        }
+      });
+    }
+    if (property != null) {
+      return createScope(fieldsInExtendedVersionOfMessageContaining(property));
     }
     Set<IEObjectDescription> descriptions = emptySet();
     return createScope(descriptions);
   }
 
+  private Property referencedProperty(ExtendMessagePropertyRef ref, List<OptionField> fields, Provider<Property> provider) {
+    OptionField previous = null;
+    boolean isFirstField = true;
+    for (OptionField field : fields) {
+      if (field == ref) return (isFirstField) ? provider.get() : propertyFrom(previous);
+      previous = field;
+      isFirstField = false;
+    }
+    return null;
+  }
+
+  private Collection <IEObjectDescription> fieldsInExtendedVersionOfMessageContaining(Property p) {
+    Message propertyType = modelFinder.messageTypeOf(p);
+    if (propertyType == null) return emptyList();
+    Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+    for (ExtendMessage extend : modelFinder.extensionsOf(propertyType)) {
+      for (MessageElement e : extend.getElements()) {
+        if (!(e instanceof Property)) continue;
+        Property optionPropertyField = (Property) e;
+        descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(optionPropertyField));
+        descriptions.add(create(optionPropertyField.getName(), optionPropertyField));
+      }
+    }
+    return descriptions;
+  }
+
+  private Property propertyFrom(OptionField field) {
+    if (field instanceof MessagePropertyRef) {
+      MessagePropertyRef ref = (MessagePropertyRef) field;
+      return ref.getMessageProperty();
+    }
+    if (field instanceof ExtendMessagePropertyRef) {
+      ExtendMessagePropertyRef ref = (ExtendMessagePropertyRef) field;
+      return ref.getExtendMessageProperty();
+    }
+    return null;
+  }
+  
   private static IScope createScope(Iterable<IEObjectDescription> descriptions) {
     return new SimpleScope(descriptions, DO_NOT_IGNORE_CASE);
   }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ScopeFinder.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ScopeFinder.java
new file mode 100644
index 0000000..7b921f4
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ScopeFinder.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.scoping;
+
+import static java.util.Collections.emptyList;
+import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents;
+
+import com.google.eclipse.protobuf.model.util.*;
+import com.google.eclipse.protobuf.parser.NonProto2;
+import com.google.eclipse.protobuf.protobuf.*;
+import com.google.eclipse.protobuf.protobuf.Package;
+import com.google.inject.Inject;
+
+import org.eclipse.emf.common.util.TreeIterator;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.*;
+import org.eclipse.xtext.resource.IEObjectDescription;
+
+import java.util.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class ScopeFinder {
+
+  @Inject private ModelFinder finder;
+  @Inject private Imports imports;
+  @Inject private Packages packages;
+  @Inject private Resources resources;
+
+  Collection<IEObjectDescription> findScope(EObject target, SearchDelegate delegate, Object criteria) {
+    Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+    EObject current = target.eContainer();
+    while (current != null) {
+      descriptions.addAll(local(current, delegate, criteria));
+      current = current.eContainer();
+    }
+    Protobuf root = finder.rootOf(target);
+    descriptions.addAll(imported(root, delegate, criteria));
+    return descriptions;
+  }
+  
+  Collection<IEObjectDescription> findScope(Protobuf root, SearchDelegate delegate, Object criteria) {
+    Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+    descriptions.addAll(local(root, delegate, criteria));
+    descriptions.addAll(imported(root, delegate, criteria));
+    return descriptions;
+  }
+
+  private Collection<IEObjectDescription> local(EObject root, SearchDelegate delegate, Object criteria) {
+    return local(root, delegate, criteria, 0);
+  }
+
+  private Collection<IEObjectDescription> local(EObject root, SearchDelegate delegate, Object criteria, int level) {
+    List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
+    for (EObject element : root.eContents()) {
+      descriptions.addAll(delegate.descriptions(element, criteria, level));
+      if (delegate.continueSearchOneLevelHigher(element)) {
+        descriptions.addAll(local(element, delegate, criteria, level + 1));
+      }
+    }
+    return descriptions;
+  }
+
+  private Collection<IEObjectDescription> imported(Protobuf root, SearchDelegate delegate, Object criteria) {
+    List<Import> allImports = finder.importsIn(root);
+    if (allImports.isEmpty()) return emptyList();
+    ResourceSet resourceSet = root.eResource().getResourceSet();
+    return imported(allImports, finder.packageOf(root), resourceSet, delegate, criteria);
+  }
+
+  private Collection<IEObjectDescription> imported(List<Import> allImports, Package aPackage,
+      ResourceSet resourceSet, SearchDelegate delegate, Object criteria) {
+    List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
+    for (Import anImport : allImports) {
+      if (imports.isImportingDescriptor(anImport)) {
+        descriptions.addAll(delegate.fromProtoDescriptor(anImport, criteria));
+        continue;
+      }
+      Resource importedResource = resources.importedResource(anImport, resourceSet);
+      Protobuf rootOfImported = finder.rootOf(importedResource);
+      if (rootOfImported instanceof NonProto2) continue;
+      if (rootOfImported != null) {
+        descriptions.addAll(publicImported(rootOfImported, delegate, criteria));
+        if (arePackagesRelated(aPackage, rootOfImported)) {
+          descriptions.addAll(local(rootOfImported, delegate, criteria));
+          continue;
+        }
+      }
+      descriptions.addAll(local(importedResource, delegate, criteria));
+    }
+    return descriptions;
+  }
+
+  private Collection<IEObjectDescription> publicImported(Protobuf root, SearchDelegate delegate, Object criteria) {
+    List<Import> allImports = finder.publicImportsIn(root);
+    if (allImports.isEmpty()) return emptyList();
+    ResourceSet resourceSet = root.eResource().getResourceSet();
+    return imported(allImports, finder.packageOf(root), resourceSet, delegate, criteria);
+  }
+
+  private boolean arePackagesRelated(Package aPackage, EObject root) {
+    Package p = finder.packageOf(root);
+    return packages.areRelated(aPackage, p);
+  }
+
+  private Collection<IEObjectDescription> local(Resource resource, SearchDelegate delegate, Object criteria) {
+    List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
+    TreeIterator<Object> contents = getAllContents(resource, true);
+    while (contents.hasNext()) {
+      Object next = contents.next();
+      descriptions.addAll(delegate.descriptions(next, criteria));
+      // TODO verify that call to 'importedNamesProvider.namesOf' is not necessary
+    }
+    return descriptions;
+  }
+}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/SearchDelegate.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/SearchDelegate.java
new file mode 100644
index 0000000..a8dd4d0
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/SearchDelegate.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.scoping;
+
+import com.google.eclipse.protobuf.protobuf.Import;
+
+import org.eclipse.xtext.resource.IEObjectDescription;
+
+import java.util.Collection;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+interface SearchDelegate {
+
+  boolean continueSearchOneLevelHigher(Object target);
+  
+  Collection<IEObjectDescription> fromProtoDescriptor(Import anImport, Object criteria);
+
+  Collection<IEObjectDescription> descriptions(Object target, Object criteria);
+
+  Collection<IEObjectDescription> descriptions(Object target, Object criteria, int level);
+}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeDescriptions.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeDescriptions.java
deleted file mode 100644
index 835d74b..0000000
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeDescriptions.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (c) 2011 Google Inc.
- *
- * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
- * Public License v1.0 which accompanies this distribution, and is available at
- *
- * http://www.eclipse.org/legal/epl-v10.html
- */
-package com.google.eclipse.protobuf.scoping;
-
-import static java.util.Collections.emptyList;
-import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents;
-import static org.eclipse.xtext.resource.EObjectDescription.create;
-
-import java.util.*;
-
-import org.eclipse.emf.common.util.*;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.resource.*;
-import org.eclipse.xtext.naming.QualifiedName;
-import org.eclipse.xtext.resource.IEObjectDescription;
-
-import com.google.eclipse.protobuf.model.util.*;
-import com.google.eclipse.protobuf.parser.NonProto2;
-import com.google.eclipse.protobuf.protobuf.*;
-import com.google.eclipse.protobuf.protobuf.Package;
-import com.google.inject.Inject;
-
-/**
- * @author alruiz@google.com (Alex Ruiz)
- */
-class TypeDescriptions {
-
-  @Inject private ProtoDescriptorProvider descriptorProvider;
-  @Inject private ModelFinder finder;
-  @Inject private Imports imports;
-  @Inject private LocalNamesProvider localNamesProvider;
-  @Inject private Packages packages;
-  @Inject private QualifiedNameDescriptions qualifiedNamesDescriptions;
-  @Inject private Resources resources;
-
-  Collection<IEObjectDescription> types(Property property) {
-    Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
-    EObject current = property.eContainer();
-    Class<Type> targetType = Type.class;
-    while (current != null) {
-      descriptions.addAll(local(current, targetType));
-      current = current.eContainer();
-    }
-    Protobuf root = finder.rootOf(property);
-    descriptions.addAll(imported(root, targetType));
-    return descriptions;
-  }
-  
-  Collection<IEObjectDescription> messages(Protobuf root) {
-    Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
-    Class<Message> targetType = Message.class;
-    descriptions.addAll(local(root, targetType));
-    descriptions.addAll(imported(root, targetType));
-    return descriptions;
-  }
-  
-  private <T extends Type> Collection<IEObjectDescription> local(EObject root, Class<T> targetType) {
-    return local(root, targetType, 0);
-  }
-
-  private <T extends Type> Collection<IEObjectDescription> local(EObject root, Class<T> targetType, int level) {
-    List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
-    for (EObject element : root.eContents()) {
-      if (!targetType.isInstance(element)) continue;
-      List<QualifiedName> names = localNamesProvider.namesOf(element);
-      int nameCount = names.size();
-      for (int i = level; i < nameCount; i++) {
-        descriptions.add(create(names.get(i), element));
-      }
-      descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(element));
-      // TODO investigate if groups can have messages, and if so, add those messages to the scope.
-      if (element instanceof Message) {
-        descriptions.addAll(local(element, targetType, level + 1));
-      }
-    }
-    return descriptions;
-  }
-
-  private <T extends Type> Collection<IEObjectDescription> imported(Protobuf root, Class<T> targetType) {
-    List<Import> allImports = finder.importsIn(root);
-    if (allImports.isEmpty()) return emptyList();
-    ResourceSet resourceSet = root.eResource().getResourceSet();
-    return imported(allImports, finder.packageOf(root), resourceSet, targetType);
-  }
-
-  private <T extends Type> Collection<IEObjectDescription> imported(List<Import> allImports, Package aPackage,
-      ResourceSet resourceSet, Class<T> targetType) {
-    List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
-    for (Import anImport : allImports) {
-      if (imports.isImportingDescriptor(anImport)) {
-        descriptions.addAll(allNative(anImport, targetType));
-        continue;
-      }
-      Resource importedResource = resources.importedResource(anImport, resourceSet);
-      Protobuf rootOfImported = finder.rootOf(importedResource);
-      if (rootOfImported instanceof NonProto2) continue;
-      if (rootOfImported != null) {
-        descriptions.addAll(publicImported(rootOfImported, targetType));
-        if (arePackagesRelated(aPackage, rootOfImported)) {
-          descriptions.addAll(local(rootOfImported, targetType));
-          continue;
-        }
-      }
-      descriptions.addAll(local(importedResource, targetType));
-    }
-    return descriptions;
-  }
-
-  private <T extends Type> Collection<IEObjectDescription> allNative(Import anImport, Class<T> targetType) {
-    List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
-    ProtoDescriptor descriptor = descriptorProvider.descriptor(anImport.getImportURI());
-    for (Type t : descriptor.allTypes()) {
-      if (!targetType.isInstance(t)) continue;
-      T type = targetType.cast(t);
-      descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(type));
-    }
-    return descriptions;
-  }
-
-  private <T extends Type> Collection<IEObjectDescription> publicImported(Protobuf root, Class<T> targetType) {
-    List<Import> allImports = finder.publicImportsIn(root);
-    if (allImports.isEmpty()) return emptyList();
-    ResourceSet resourceSet = root.eResource().getResourceSet();
-    return imported(allImports, finder.packageOf(root), resourceSet, targetType);
-  }
-
-  private boolean arePackagesRelated(Package aPackage, EObject root) {
-    Package p = finder.packageOf(root);
-    return packages.areRelated(aPackage, p);
-  }
-
-  private <T extends Type> Collection<IEObjectDescription> local(Resource resource, Class<T> targetType) {
-    List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
-    TreeIterator<Object> contents = getAllContents(resource, true);
-    while (contents.hasNext()) {
-      Object next = contents.next();
-      if (!targetType.isInstance(next)) continue;
-      T type = targetType.cast(next);
-      descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(type));
-      // TODO verify that call to 'importedNamesProvider.namesOf' is not necessary
-    }
-    return descriptions;
-  }
-}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeSearchDelegate.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeSearchDelegate.java
new file mode 100644
index 0000000..493803b
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeSearchDelegate.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.scoping;
+
+import static java.util.Collections.emptySet;
+import static org.eclipse.xtext.resource.EObjectDescription.create;
+
+import com.google.eclipse.protobuf.protobuf.*;
+import com.google.inject.Inject;
+
+import org.eclipse.xtext.naming.QualifiedName;
+import org.eclipse.xtext.resource.IEObjectDescription;
+
+import java.util.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class TypeSearchDelegate implements SearchDelegate {
+
+  @Inject private ProtoDescriptorProvider descriptorProvider;
+  @Inject private LocalNamesProvider localNamesProvider;
+  @Inject private QualifiedNameDescriptions qualifiedNamesDescriptions;
+
+  @Override public boolean continueSearchOneLevelHigher(Object target) {
+    return target instanceof Message;
+  }
+
+  @Override public Collection<IEObjectDescription> fromProtoDescriptor(Import anImport, Object criteria) {
+    Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+    Class<? extends Type> targetType = targetTypeFrom(criteria);
+    ProtoDescriptor descriptor = descriptorProvider.descriptor(anImport.getImportURI());
+    for (Type type : descriptor.allTypes()) {
+      if (!targetType.isInstance(type)) continue;
+      descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(type));
+    }
+    return descriptions;
+  }
+  
+  @Override public Collection<IEObjectDescription> descriptions(Object target, Object criteria) {
+    Class<? extends Type> targetType = targetTypeFrom(criteria);
+    if (!targetType.isInstance(target)) return emptySet();
+    Type type = targetType.cast(target);
+    return qualifiedNamesDescriptions.qualifiedNames(type);
+  }
+
+  @Override public Collection<IEObjectDescription> descriptions(Object target, Object criteria, int level) {
+    Class<? extends Type> targetType = targetTypeFrom(criteria);
+    if (!targetType.isInstance(target)) return emptySet();
+    Type type = targetType.cast(target);
+    Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+    List<QualifiedName> names = localNamesProvider.namesOf(type);
+    int nameCount = names.size();
+    for (int i = level; i < nameCount; i++) {
+      descriptions.add(create(names.get(i), type));
+    }
+    descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(type));
+    return descriptions;
+  }
+  
+  @SuppressWarnings("unchecked") 
+  private Class<? extends Type> targetTypeFrom(Object criteria) {
+    if (!(criteria instanceof Class)) 
+      throw new IllegalArgumentException("Search criteria should be Class<? extends Type>");
+    return (Class<? extends Type>) criteria;
+  }
+}