In progress: [Issue 199] Add ability to navigate to proto element from
generated C++ code.

* Added support for nested messages. 
* Code cleanup. 
* Added tests.
diff --git a/com.google.eclipse.protobuf.cdt.test/.classpath b/com.google.eclipse.protobuf.cdt.test/.classpath
new file mode 100644
index 0000000..ad32c83
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt.test/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/com.google.eclipse.protobuf.cdt.test/.gitignore b/com.google.eclipse.protobuf.cdt.test/.gitignore
new file mode 100644
index 0000000..40a85ff
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt.test/.gitignore
@@ -0,0 +1 @@
+/.settings
diff --git a/com.google.eclipse.protobuf.cdt.test/.project b/com.google.eclipse.protobuf.cdt.test/.project
new file mode 100644
index 0000000..5c0fd35
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt.test/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>com.google.eclipse.protobuf.cdt.test</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/com.google.eclipse.protobuf.cdt.test/META-INF/MANIFEST.MF b/com.google.eclipse.protobuf.cdt.test/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..09d731b
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt.test/META-INF/MANIFEST.MF
@@ -0,0 +1,10 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Unit tests for com.google.eclipse.protobuf.cdt
+Bundle-SymbolicName: com.google.eclipse.protobuf.cdt.test
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: Google, Inc.
+Fragment-Host: com.google.eclipse.protobuf.cdt;bundle-version="1.0.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Require-Bundle: org.junit;bundle-version="4.8.2",
+ org.mockito;bundle-version="1.8.5"
diff --git a/com.google.eclipse.protobuf.cdt.test/build.properties b/com.google.eclipse.protobuf.cdt.test/build.properties
new file mode 100644
index 0000000..34d2e4d
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt.test/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .
diff --git a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/actions/ClassTypeQualifiedNameBuilder_createQualifiedNamesFrom_Test.java b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/actions/ClassTypeQualifiedNameBuilder_createQualifiedNamesFrom_Test.java
new file mode 100644
index 0000000..1fcc16d
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/actions/ClassTypeQualifiedNameBuilder_createQualifiedNamesFrom_Test.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012 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.cdt.actions;
+
+import static com.google.eclipse.protobuf.junit.core.UnitTestModule.unitTestModule;
+import static com.google.eclipse.protobuf.junit.core.XtextRule.overrideRuntimeModuleWith;
+import static java.util.Collections.singletonList;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.*;
+
+import java.util.List;
+
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
+import org.eclipse.cdt.internal.core.dom.parser.c.CASTName;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.*;
+import org.eclipse.xtext.naming.QualifiedName;
+import org.junit.*;
+
+import com.google.eclipse.protobuf.cdt.ProtobufCdtModule;
+import com.google.eclipse.protobuf.junit.core.*;
+import com.google.inject.Inject;
+
+/**
+ * Tests for <code>{@link ClassTypeQualifiedNameBuilder#createQualifiedNamesFrom(CPPClassType)}</code>
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+@SuppressWarnings("restriction")
+public class ClassTypeQualifiedNameBuilder_createQualifiedNamesFrom_Test {
+  @Rule public XtextRule xtext = overrideRuntimeModuleWith(unitTestModule(), new ProtobufCdtModule(), new TestModule());
+
+  @Inject private CPPClassType classType;
+  @Inject private QualifiedNameFactory qualifiedNameFactory;
+  @Inject private ClassTypeQualifiedNameBuilder nameBuilder;
+
+  @Test public void should_return_qualified_names_for_class_type() {
+    expectClassTypeToExtendProtoMessage();
+    String[] segments = { "com", "google", "proto", "Test" };
+    when(classType.getQualifiedName()).thenReturn(segments);
+    List<QualifiedName> expected = singletonList(QualifiedName.create(segments));
+    when(qualifiedNameFactory.createQualifiedNamesForComplexType(segments)).thenReturn(expected);
+    assertThat(nameBuilder.createQualifiedNamesFrom(classType), equalTo(expected));
+  }
+
+  private void expectClassTypeToExtendProtoMessage() {
+    ICPPBase base = mock(ICPPBase.class);
+    when(classType.getBases()).thenReturn(new ICPPBase[] { base });
+    when(base.getBaseClassSpecifierName()).thenReturn(createQualifiedName("google", "protobuf", "Message"));
+  }
+
+  private CPPASTQualifiedName createQualifiedName(String...segments) {
+    CPPASTQualifiedName qualifiedName = new CPPASTQualifiedName();
+    for (String segment : segments) {
+      qualifiedName.addName(new CASTName(segment.toCharArray()));
+    }
+    qualifiedName.setFullyQualified(true);
+    return qualifiedName;
+  }
+
+  private static class TestModule extends AbstractTestModule {
+    @Override protected void configure() {
+      mockAndBind(CPPClassType.class);
+      mockAndBind(QualifiedNameFactory.class);
+    }
+  }
+}
\ No newline at end of file
diff --git a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/actions/QualifiedNameFactory_createQualifiedNamesForComplexType_Test.java b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/actions/QualifiedNameFactory_createQualifiedNamesForComplexType_Test.java
new file mode 100644
index 0000000..f21019f
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/actions/QualifiedNameFactory_createQualifiedNamesForComplexType_Test.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012 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.cdt.actions;
+
+import static com.google.eclipse.protobuf.cdt.junit.QualifiedNamesContain.containOnly;
+import static com.google.eclipse.protobuf.junit.core.UnitTestModule.unitTestModule;
+import static com.google.eclipse.protobuf.junit.core.XtextRule.overrideRuntimeModuleWith;
+import static org.junit.Assert.assertThat;
+
+import java.util.List;
+
+import org.eclipse.xtext.naming.QualifiedName;
+import org.junit.*;
+
+import com.google.eclipse.protobuf.cdt.ProtobufCdtModule;
+import com.google.eclipse.protobuf.junit.core.XtextRule;
+import com.google.inject.Inject;
+
+/**
+ * Tests for <code>{@link QualifiedNameFactory#createQualifiedNamesForComplexType(String[])}</code>
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class QualifiedNameFactory_createQualifiedNamesForComplexType_Test {
+  @Rule public XtextRule xtext = overrideRuntimeModuleWith(unitTestModule(), new ProtobufCdtModule());
+
+  @Inject private QualifiedNameFactory qualifiedNameFactory;
+
+  @Test public void should_return_single_qualified_name_for_top_level_type() {
+    String[] segments = { "com", "google", "proto", "Test" };
+    List<QualifiedName> qualifiedNames = qualifiedNameFactory.createQualifiedNamesForComplexType(segments);
+    assertThat(qualifiedNames, containOnly("com.google.proto.Test"));
+  }
+
+  @Test public void should_split_in_underscore_for_one_level_nesting() {
+    String[] segments = { "com", "google", "proto", "Test_Inner" };
+    List<QualifiedName> qualifiedNames = qualifiedNameFactory.createQualifiedNamesForComplexType(segments);
+    assertThat(qualifiedNames, containOnly("com.google.proto.Test_Inner", "com.google.proto.Test.Inner"));
+  }
+
+  @Test public void should_split_in_underscore_for_multiple_level_nesting() {
+    String[] segments = { "com", "google", "proto", "Test_Inner_Inner" };
+    List<QualifiedName> qualifiedNames = qualifiedNameFactory.createQualifiedNamesForComplexType(segments);
+    assertThat(qualifiedNames, containOnly("com.google.proto.Test_Inner_Inner", "com.google.proto.Test.Inner.Inner"));
+  }}
diff --git a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/junit/QualifiedNamesContain.java b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/junit/QualifiedNamesContain.java
new file mode 100644
index 0000000..e2f213a
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/junit/QualifiedNamesContain.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012 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.cdt.junit;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+import java.util.List;
+
+import org.eclipse.xtext.naming.QualifiedName;
+import org.hamcrest.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class QualifiedNamesContain extends BaseMatcher<List<QualifiedName>> {
+  private final List<String> qualifiedNames;
+
+  public static QualifiedNamesContain containOnly(String...qualifiedNames) {
+    return new QualifiedNamesContain(qualifiedNames);
+  }
+
+  private QualifiedNamesContain(String[] qualifiedNames) {
+    this.qualifiedNames = newArrayList(qualifiedNames);
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override public boolean matches(Object item) {
+    if (!(item instanceof List)) {
+      return false;
+    }
+    List<String> copy = newArrayList(qualifiedNames);
+    List<QualifiedName> actualNames = (List<QualifiedName>) item;
+    for (QualifiedName actual : actualNames) {
+      String expected = actual.toString();
+      copy.remove(expected);
+    }
+    return copy.isEmpty();
+  }
+
+  @Override public void describeTo(Description description) {
+    description.appendValue(qualifiedNames);
+  }
+}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ClassTypeQualifiedNameBuilder.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ClassTypeQualifiedNameBuilder.java
index b521a6a..907fa26 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ClassTypeQualifiedNameBuilder.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ClassTypeQualifiedNameBuilder.java
@@ -8,26 +8,28 @@
  */
 package com.google.eclipse.protobuf.cdt.actions;
 
-import static java.util.Collections.*;
+import static java.util.Collections.emptyList;
 
-import java.util.Collection;
+import java.util.List;
 
 import org.eclipse.cdt.core.dom.IName;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
 import org.eclipse.cdt.internal.core.dom.parser.cpp.*;
 import org.eclipse.xtext.naming.QualifiedName;
 
-import com.google.inject.Singleton;
+import com.google.inject.*;
 
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
 @SuppressWarnings("restriction")
 @Singleton class ClassTypeQualifiedNameBuilder {
-  public Collection<QualifiedName> createQualifiedNamesFrom(CPPClassType classType) {
+  @Inject QualifiedNameFactory qualifiedNameFactory;
+
+  public List<QualifiedName> createQualifiedNamesFrom(CPPClassType classType) {
     if (isMessage(classType)) {
       String[] segments = classType.getQualifiedName();
-      return singletonList(QualifiedName.create(segments));
+      return qualifiedNameFactory.createQualifiedNamesForComplexType(segments);
     }
     return emptyList();
   }
@@ -45,7 +47,7 @@
     if (!qualifiedName.isFullyQualified()) {
       return false;
     }
-    String rawSignature = qualifiedName.getRawSignature();
-    return "::google::protobuf::Message".equals(rawSignature);
+    String qualifiedNameAsText = qualifiedName.toString();
+    return "::google::protobuf::Message".equals(qualifiedNameAsText);
   }
 }
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ModelObjectDefinitionQueryBuilder.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ModelObjectDefinitionQueryBuilder.java
index dcb0e0e..c5f9320 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ModelObjectDefinitionQueryBuilder.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ModelObjectDefinitionQueryBuilder.java
@@ -8,14 +8,12 @@
  */
 package com.google.eclipse.protobuf.cdt.actions;
 
-import static com.google.common.collect.Lists.newArrayList;
 import static com.google.eclipse.protobuf.ui.editor.ModelObjectDefinitionNavigator.Query.query;
 import static java.lang.Math.max;
-import static java.util.Collections.emptyList;
 import static org.eclipse.cdt.internal.ui.editor.ASTProvider.WAIT_NO;
 import static org.eclipse.core.runtime.Status.*;
 
-import java.util.*;
+import java.util.Collection;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.eclipse.cdt.core.dom.ast.*;
@@ -40,16 +38,16 @@
   @Inject private ClassTypeQualifiedNameBuilder nameBuilder;
   @Inject private ProtoFilePathFinder pathFinder;
 
-  Collection<Query> buildQueries(final IEditorPart editor, final ITextSelection selection) {
+  Query buildQuery(final IEditorPart editor, final ITextSelection selection) {
     final IPath protoFilePath = pathFinder.findProtoFilePath(editor);
     if (protoFilePath == null) {
-      return emptyList();
+      return null;
     }
     IWorkingCopy workingCopy = CUIPlugin.getDefault().getWorkingCopyManager().getWorkingCopy(editor.getEditorInput());
     if (workingCopy == null) {
-      return emptyList();
+      return null;
     }
-    final AtomicReference<Collection<Query>> queriesReference = new AtomicReference<Collection<Query>>();
+    final AtomicReference<Query> queriesReference = new AtomicReference<Query>();
     ASTProvider astProvider = ASTProvider.getASTProvider();
     IStatus status = astProvider.runOnAST(workingCopy, WAIT_NO, null, new ASTRunnable() {
       @Override public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) throws CoreException {
@@ -70,11 +68,7 @@
             if (qualifiedNames.isEmpty()) {
               return CANCEL_STATUS;
             }
-            List<Query> queries = newArrayList();
-            for (QualifiedName qualifiedName : qualifiedNames) {
-              queries.add(query(qualifiedName, protoFilePath));
-            }
-            queriesReference.set(queries);
+            queriesReference.set(query(qualifiedNames, protoFilePath));
             return OK_STATUS;
           }
         }
@@ -82,7 +76,7 @@
       }
     });
     if (status == CANCEL_STATUS) {
-      return emptyList();
+      return null;
     }
     return queriesReference.get();
   }
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/NavigationJobs.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/NavigationJobs.java
index a46878c..4b9ebe3 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/NavigationJobs.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/NavigationJobs.java
@@ -10,8 +10,6 @@
 
 import static org.eclipse.core.runtime.Status.OK_STATUS;
 
-import java.util.Collection;
-
 import org.eclipse.core.runtime.*;
 import org.eclipse.ui.progress.UIJob;
 
@@ -25,15 +23,10 @@
 class NavigationJobs {
   @Inject private ModelObjectDefinitionNavigator navigator;
 
-  void scheduleUsing(final Collection<Query> queries) {
+  void scheduleUsing(final Query query) {
     UIJob job = new UIJob("Navigating to .proto file") {
       @Override public IStatus runInUIThread(IProgressMonitor monitor) {
-        for (Query query : queries) {
-          IStatus result = navigator.navigateToDefinition(query);
-          if (result.equals(OK_STATUS)) {
-            break;
-          }
-        }
+        navigator.navigateToDefinition(query);
         return OK_STATUS;
       }
     };
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/OpenProtoDeclarationAction.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/OpenProtoDeclarationAction.java
index 0dd8c35..25201bc 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/OpenProtoDeclarationAction.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/OpenProtoDeclarationAction.java
@@ -8,8 +8,6 @@
  */
 package com.google.eclipse.protobuf.cdt.actions;
 
-import java.util.Collection;
-
 import org.eclipse.jface.action.IAction;
 import org.eclipse.jface.text.ITextSelection;
 import org.eclipse.jface.viewers.ISelection;
@@ -34,9 +32,9 @@
     if (editor == null || selection == null) {
       return;
     }
-    Collection<Query> queries = queryBuilder.buildQueries(editor, selection);
-    if (!queries.isEmpty()) {
-      navigationJobs.scheduleUsing(queries);
+    Query query = queryBuilder.buildQuery(editor, selection);
+    if (query != null) {
+      navigationJobs.scheduleUsing(query);
     }
   }
 
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/QualifiedNameBuilder.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/QualifiedNameBuilder.java
deleted file mode 100644
index 2afab3e..0000000
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/QualifiedNameBuilder.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (c) 2012 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.cdt.actions;
-
-import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
-import org.eclipse.xtext.naming.QualifiedName;
-
-/**
- * @author alruiz@google.com (Alex Ruiz)
- */
-@SuppressWarnings("restriction")
-interface QualifiedNameBuilder {
-  QualifiedName createQualifiedNameFrom(ASTNode node);
-}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/QualifiedNameFactory.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/QualifiedNameFactory.java
new file mode 100644
index 0000000..98389a8
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/QualifiedNameFactory.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012 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.cdt.actions;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static java.util.Collections.unmodifiableList;
+
+import java.util.List;
+
+import org.eclipse.xtext.naming.QualifiedName;
+
+import com.google.eclipse.protobuf.model.util.QualifiedNames;
+import com.google.inject.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+@Singleton class QualifiedNameFactory {
+  @Inject private QualifiedNames qualifiedNames;
+
+  List<QualifiedName> createQualifiedNamesForComplexType(String[] segments) {
+    List<QualifiedName> names = newArrayList();
+    names.add(QualifiedName.create(segments));
+    int lastSegmentIndex = segments.length - 1;
+    String messageName = segments[lastSegmentIndex];
+    if (messageName.contains("_")) {
+      String[] hierarchicalNames = messageName.split("_");
+      List<String> newSegments = newArrayList(segments);
+      newSegments.remove(lastSegmentIndex);
+      newSegments.addAll(newArrayList(hierarchicalNames));
+      names.add(qualifiedNames.createFqn(newSegments));
+    }
+    return unmodifiableList(names);
+  }
+}
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/resource/ModelObjectLocationLookup_findModelObjectUri_Test.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/resource/ModelObjectLocationLookup_findModelObjectUri_Test.java
index 51bdba7..afa5d16 100644
--- a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/resource/ModelObjectLocationLookup_findModelObjectUri_Test.java
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/resource/ModelObjectLocationLookup_findModelObjectUri_Test.java
@@ -10,6 +10,7 @@
 
 import static com.google.eclipse.protobuf.junit.core.IntegrationTestModule.integrationTestModule;
 import static com.google.eclipse.protobuf.junit.core.XtextRule.overrideRuntimeModuleWith;
+import static java.util.Collections.singletonList;
 import static org.hamcrest.core.IsEqual.equalTo;
 import static org.junit.Assert.*;
 
@@ -26,7 +27,7 @@
 import com.google.inject.Inject;
 
 /**
- * Tests for <code>{@link ModelObjectLocationLookup#findModelObjectUri(QualifiedName, IPath)}</code>
+ * Tests for <code>{@link ModelObjectLocationLookup#findModelObjectUri(Iterable, IPath)}</code>
  *
  * @author alruiz@google.com (Alex Ruiz)
  */
@@ -46,8 +47,8 @@
   @Test public void should_find_URI_of_model_object_given_its_qualified_name() {
     XtextResource resource = xtext.resource();
     addToXtextIndex(resource);
-    QualifiedName qualifiedName = fqnConverter.toQualifiedName("com.google.proto.Type");
-    URI foundUri = lookup.findModelObjectUri(qualifiedName, pathOf(resource));
+    Iterable<QualifiedName> qualifiedNames = singletonList(fqnConverter.toQualifiedName("com.google.proto.Type"));
+    URI foundUri = lookup.findModelObjectUri(qualifiedNames, pathOf(resource));
     Enum anEnum = xtext.find("Type", Enum.class);
     String fragment = resource.getURIFragment(anEnum);
     URI expectedUri = resource.getURI().appendFragment(fragment);
@@ -64,8 +65,8 @@
   // message Person {}
   @Test public void should_return_null_if_file_name_is_equal_but_file_path_is_not() {
     addToXtextIndex(xtext.resource());
-    QualifiedName qualifiedName = fqnConverter.toQualifiedName("com.google.proto.Person");
-    URI foundUri = lookup.findModelObjectUri(qualifiedName, new Path("/test/src/protos/mytestmodel.proto"));
+    Iterable<QualifiedName> qualifiedNames = singletonList(fqnConverter.toQualifiedName("com.google.proto.Person"));
+    URI foundUri = lookup.findModelObjectUri(qualifiedNames, new Path("/test/src/protos/mytestmodel.proto"));
     assertNull(foundUri);
   }
 
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/editor/ModelObjectDefinitionNavigator_navigateToDefinition_Test.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/editor/ModelObjectDefinitionNavigator_navigateToDefinition_Test.java
index 1c3b020..6213098 100644
--- a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/editor/ModelObjectDefinitionNavigator_navigateToDefinition_Test.java
+++ b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/editor/ModelObjectDefinitionNavigator_navigateToDefinition_Test.java
@@ -11,6 +11,7 @@
 import static com.google.eclipse.protobuf.junit.core.UnitTestModule.unitTestModule;
 import static com.google.eclipse.protobuf.junit.core.XtextRule.overrideRuntimeModuleWith;
 import static com.google.eclipse.protobuf.ui.editor.ModelObjectDefinitionNavigator.Query.query;
+import static java.util.Collections.singletonList;
 import static org.eclipse.core.runtime.Status.*;
 import static org.eclipse.emf.common.util.URI.createURI;
 import static org.hamcrest.core.IsEqual.equalTo;
@@ -50,17 +51,17 @@
 
   @Test public void should_navigate_to_model_object_if_URI_is_found() {
     URI uri = createURI("file:/usr/local/project/src/protos/test.proto");
-    QualifiedName qualifiedName = fqnConverter.toQualifiedName("com.google.proto.Type");
-    when(locationLookup.findModelObjectUri(qualifiedName, filePath)).thenReturn(uri);
-    IStatus result = navigator.navigateToDefinition(query(qualifiedName, filePath));
+    Iterable<QualifiedName> qualifiedNames = singletonList(fqnConverter.toQualifiedName("com.google.proto.Type"));
+    when(locationLookup.findModelObjectUri(qualifiedNames, filePath)).thenReturn(uri);
+    IStatus result = navigator.navigateToDefinition(query(qualifiedNames, filePath));
     assertThat(result, equalTo(OK_STATUS));
     verify(editorOpener).open(uri, true);
   }
 
   @Test public void should_not_navigate_to_model_object_if_URI_is_not_found() {
-    QualifiedName qualifiedName = fqnConverter.toQualifiedName("com.google.proto.Person");
-    when(locationLookup.findModelObjectUri(qualifiedName, filePath)).thenReturn(null);
-    IStatus result = navigator.navigateToDefinition(query(qualifiedName, filePath));
+    Iterable<QualifiedName> qualifiedNames = singletonList(fqnConverter.toQualifiedName("com.google.proto.Person"));
+    when(locationLookup.findModelObjectUri(qualifiedNames, filePath)).thenReturn(null);
+    IStatus result = navigator.navigateToDefinition(query(qualifiedNames, filePath));
     assertThat(result, equalTo(CANCEL_STATUS));
     verifyZeroInteractions(editorOpener);
   }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ModelObjectDefinitionNavigator.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ModelObjectDefinitionNavigator.java
index 0a1c3c2..f0393c7 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ModelObjectDefinitionNavigator.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ModelObjectDefinitionNavigator.java
@@ -8,6 +8,7 @@
  */
 package com.google.eclipse.protobuf.ui.editor;
 
+import static com.google.common.collect.Lists.newLinkedList;
 import static org.eclipse.core.runtime.Status.*;
 
 import org.eclipse.core.runtime.*;
@@ -28,13 +29,13 @@
   @Inject private IURIEditorOpener editorOpener;
 
   /**
-   * Navigates to the definition of the model object whose qualified name matches the given one. This method will open
-   * the file containing the model object definition if necessary.
+   * Navigates to the definition of the model object whose qualified name matches any of the given ones. This method
+   * will open the file containing the model object definition if necessary.
    * @param query information needed to find the object model to navigate to.
    * @return the result of the operation.
     */
   public IStatus navigateToDefinition(Query query) {
-    URI uri = locationLookup.findModelObjectUri(query.qualifiedName, query.filePath);
+    URI uri = locationLookup.findModelObjectUri(query.qualifiedNames, query.filePath);
     if (uri != null) {
       editorOpener.open(uri, true);
       return OK_STATUS;
@@ -48,22 +49,22 @@
    * @author alruiz@google.com (Alex Ruiz)
    */
   public static class Query {
-    final QualifiedName qualifiedName;
+    final Iterable<QualifiedName> qualifiedNames;
     final IPath filePath;
 
     /**
      * Creates a new <code>{@link Query}</code>, to be used by
      * <code>{@link ModelObjectDefinitionNavigator#navigateToDefinition(Query)}</code>.
-     * @param qualifiedName the qualified name to match.
+     * @param qualifiedNames all the possible qualified names the model object to look for may have.
      * @param filePath the path and name of the file where to perform the lookup.
      * @return the created {@code Query}.
      */
-    public static Query query(QualifiedName qualifiedName, IPath filePath) {
-      return new Query(qualifiedName, filePath);
+    public static Query query(Iterable<QualifiedName> qualifiedNames, IPath filePath) {
+      return new Query(qualifiedNames, filePath);
     }
 
-    private Query(QualifiedName qualifiedName, IPath filePath) {
-      this.qualifiedName = qualifiedName;
+    private Query(Iterable<QualifiedName> qualifiedNames, IPath filePath) {
+      this.qualifiedNames = newLinkedList(qualifiedNames);
       this.filePath = filePath;
     }
   }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/ModelObjectLocationLookup.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/ModelObjectLocationLookup.java
index 83e093e..4c82a51 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/ModelObjectLocationLookup.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/ModelObjectLocationLookup.java
@@ -27,21 +27,23 @@
   @Inject private IResourceDescriptions xtextIndex;
 
   /**
-   * Finds the URI of a model object whose qualified name matches the given one.
-   * @param qualifiedName the qualified name to match.
+   * Finds the URI of a model object whose qualified name matches any of the given ones.
+   * @param qualifiedNames all the possible qualified names the model object to look for may have.
    * @param filePath the path and name of the file where to perform the lookup.
-   * @return the URI  of a model object whose qualified name matches the given one, or {@code null} if a matching model
-   * object cannot be found.
+   * @return the URI of a model object whose qualified name matches any of the given ones, or {@code null} if a
+   * matching model object cannot be found.
    */
-  public URI findModelObjectUri(QualifiedName qualifiedName, IPath filePath) {
+  public URI findModelObjectUri(Iterable<QualifiedName> qualifiedNames, IPath filePath) {
     for (IResourceDescription resourceDescription : xtextIndex.getAllResourceDescriptions()) {
       URI resourceUri = resourceDescription.getURI();
       if (paths.areReferringToSameFile(filePath, resourceUri)) {
         // we found the resource we are looking for.
         for (IEObjectDescription exported : resourceDescription.getExportedObjects()) {
           QualifiedName modelObjectQualifiedName = exported.getQualifiedName();
-          if (qualifiedName.equals(modelObjectQualifiedName)) {
-            return exported.getEObjectURI();
+          for (QualifiedName qualifiedName : qualifiedNames) {
+            if (qualifiedName.equals(modelObjectQualifiedName)) {
+              return exported.getEObjectURI();
+            }
           }
         }
         break;