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

Made navigation from C++ class to message definition *even more*
efficient.
diff --git a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/mapping/ClassMappingStrategy_createMappingFrom_Test.java b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/mapping/ClassMappingStrategy_createMappingFrom_Test.java
index bbf3a63..b72db47 100644
--- a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/mapping/ClassMappingStrategy_createMappingFrom_Test.java
+++ b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/mapping/ClassMappingStrategy_createMappingFrom_Test.java
@@ -43,7 +43,7 @@
     List<String> segments = newArrayList("com", "google", "proto", "Test");
     when(bindings.qualifiedNameOf(classType)).thenReturn(segments);
     CppToProtobufMapping mapping = mappingStrategy.createMappingFrom(classType);
-    assertThat(mapping.qualifiedNameSegments(), equalTo(segments));
+    assertThat(mapping.qualifiedName(), equalTo(segments));
     assertThat(mapping.type(), equalTo(MESSAGE));
   }
 
diff --git a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/MessageMatcherStrategy_matchingProtobufElementLocations_Test.java b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/MessageMatcherStrategy_matchingProtobufElementLocations_Test.java
index da9064d..9969a53 100644
--- a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/MessageMatcherStrategy_matchingProtobufElementLocations_Test.java
+++ b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/MessageMatcherStrategy_matchingProtobufElementLocations_Test.java
@@ -8,10 +8,11 @@
  */
 package com.google.eclipse.protobuf.cdt.matching;
 
-import static com.google.common.collect.Lists.newArrayList;
-import static com.google.eclipse.protobuf.cdt.matching.URIsReferToEObjects.referTo;
+import static com.google.eclipse.protobuf.cdt.matching.Resources.eObjects;
+import static com.google.eclipse.protobuf.cdt.util.ExtendedListIterator.newIterator;
 import static com.google.eclipse.protobuf.junit.core.UnitTestModule.unitTestModule;
 import static com.google.eclipse.protobuf.junit.core.XtextRule.overrideRuntimeModuleWith;
+import static org.hamcrest.collection.IsCollectionContaining.hasItems;
 import static org.junit.Assert.assertThat;
 
 import java.util.List;
@@ -20,12 +21,13 @@
 import org.eclipse.emf.ecore.EObject;
 import org.junit.*;
 
+import com.google.eclipse.protobuf.cdt.util.ExtendedIterator;
 import com.google.eclipse.protobuf.junit.core.XtextRule;
 import com.google.eclipse.protobuf.protobuf.Message;
 import com.google.inject.Inject;
 
 /**
- * Tests for <code>{@link MessageMatcherStrategy#matchingProtobufElementLocations(EObject, List)}</code>
+ * Tests for <code>{@link MessageMatcherStrategy#matchingProtobufElementLocations(EObject, ExtendedIterator)}</code>
  *
  * @author alruiz@google.com (Alex Ruiz)
  */
@@ -40,9 +42,9 @@
   //
   // message Address {}
   @Test public void should_find_top_level_perfect_match() {
-    List<URI> locations = matcher.matchingProtobufElementLocations(xtext.root(), newArrayList("Address"));
-    Message message = xtext.find("Address", Message.class);
-    assertThat(locations, referTo(message));
+    List<URI> locations = matcher.matchingProtobufElementLocations(xtext.root(), newIterator("Address"));
+    EObject message = xtext.find("Address", Message.class);
+    assertThat(eObjectsFrom(locations), hasItems(message));
   }
 
   // syntax = "proto2";
@@ -51,9 +53,9 @@
   //   message Address {}
   // }
   @Test public void should_find_nested_perfect_match() {
-    List<URI> locations = matcher.matchingProtobufElementLocations(xtext.root(), newArrayList("Person", "Address"));
-    Message message = xtext.find("Address", Message.class);
-    assertThat(locations, referTo(message));
+    List<URI> locations = matcher.matchingProtobufElementLocations(xtext.root(), newIterator("Person", "Address"));
+    EObject message = xtext.find("Address", Message.class);
+    assertThat(eObjectsFrom(locations), hasItems(message));
   }
 
   // syntax = "proto2";
@@ -64,9 +66,9 @@
   //   }
   // }
   @Test public void should_find_nested_match_1() {
-    List<URI> locations = matcher.matchingProtobufElementLocations(xtext.root(), newArrayList("Person_Address_Type"));
-    Message message = xtext.find("Type", Message.class);
-    assertThat(locations, referTo(message));
+    List<URI> locations = matcher.matchingProtobufElementLocations(xtext.root(), newIterator("Person_Address_Type"));
+    EObject message = xtext.find("Type", Message.class);
+    assertThat(eObjectsFrom(locations), hasItems(message));
   }
 
   // syntax = "proto2";
@@ -75,9 +77,9 @@
   //   message Type {}
   // }
   @Test public void should_find_nested_match_2() {
-    List<URI> locations = matcher.matchingProtobufElementLocations(xtext.root(), newArrayList("Person_Address_Type"));
-    Message message = xtext.find("Type", Message.class);
-    assertThat(locations, referTo(message));
+    List<URI> locations = matcher.matchingProtobufElementLocations(xtext.root(), newIterator("Person_Address_Type"));
+    EObject message = xtext.find("Type", Message.class);
+    assertThat(eObjectsFrom(locations), hasItems(message));
   }
 
   // syntax = "proto2";
@@ -86,8 +88,43 @@
   //   message Address_Type {}
   // }
   @Test public void should_find_nested_match_3() {
-    List<URI> locations = matcher.matchingProtobufElementLocations(xtext.root(), newArrayList("Person_Address_Type"));
-    Message message = xtext.find("Address_Type", Message.class);
-    assertThat(locations, referTo(message));
+    List<URI> locations = matcher.matchingProtobufElementLocations(xtext.root(), newIterator("Person_Address_Type"));
+    EObject message = xtext.find("Address_Type", Message.class);
+    assertThat(eObjectsFrom(locations), hasItems(message));
+  }
+
+  // syntax = "proto2";
+  //
+  // message Person {
+  //   message Address {
+  //     message Name {}
+  //     message Type {}
+  //   }
+  // }
+  @Test public void should_find_nested_match_4() {
+    List<URI> locations = matcher.matchingProtobufElementLocations(xtext.root(), newIterator("Person_Address", "Type"));
+    EObject message = xtext.find("Type", Message.class);
+    assertThat(eObjectsFrom(locations), hasItems(message));
+  }
+
+  // syntax = "proto2";
+  //
+  // message Person_Address {
+  //   message Type{}
+  // }
+  //
+  // message Person {
+  //   message Address {
+  //     message Type {}
+  //   }
+  // }
+  @Test public void should_find_nested_match_5() {
+    List<URI> locations = matcher.matchingProtobufElementLocations(xtext.root(), newIterator("Person_Address", "Type"));
+    EObject[] messages = { xtext.find("Type{}", 4, Message.class), xtext.find("Type {}", 4, Message.class) };
+    assertThat(eObjectsFrom(locations), hasItems(messages));
+  }
+
+  private List<EObject> eObjectsFrom(List<URI> locations) {
+    return eObjects(xtext.resource(), locations);
   }
 }
diff --git a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/Resources.java b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/Resources.java
new file mode 100644
index 0000000..d1f2177
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/Resources.java
@@ -0,0 +1,34 @@
+/*
+ * 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.matching;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static java.util.Collections.unmodifiableList;
+
+import java.util.List;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.resource.XtextResource;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+final class Resources {
+
+  static List<EObject> eObjects(XtextResource resource, List<URI> uris) {
+    List<EObject> found = newArrayList();
+    for (URI uri : uris) {
+      found.add(resource.getEObject(uri.fragment()));
+    }
+    return unmodifiableList(found);
+  }
+
+  private Resources() {}
+}
diff --git a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/util/ExtendedListIterator_Test.java b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/util/ExtendedListIterator_Test.java
new file mode 100644
index 0000000..38ff908
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/util/ExtendedListIterator_Test.java
@@ -0,0 +1,67 @@
+/*
+ * 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.util;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.hamcrest.collection.IsCollectionContaining.hasItems;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.*;
+
+import java.util.List;
+
+import org.junit.*;
+
+/**
+ * Tests for <code>{@link ExtendedListIterator}</code>.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class ExtendedListIterator_Test {
+  private List<String> list;
+  private ExtendedListIterator<String> iterator;
+
+  @Before public void setUp() {
+    list = newArrayList("Luke", "Yoda", "Leia");
+    iterator = new ExtendedListIterator<String>(list);
+  }
+
+  @Test public void should_iterate_through_list() {
+    assertTrue(iterator.hasNext());
+    assertThat(iterator.next(), equalTo("Luke"));
+    assertTrue(iterator.hasNext());
+    assertThat(iterator.next(), equalTo("Yoda"));
+    assertTrue(iterator.hasNext());
+    assertThat(iterator.next(), equalTo("Leia"));
+    assertFalse(iterator.hasNext());
+  }
+
+  @Test public void should_return_elements_that_have_not_been_visited_yet() {
+    assertThat(contentsOf(iterator.notRetrievedYet()), hasItems("Luke", "Yoda", "Leia"));
+    iterator.next();
+    assertThat(contentsOf(iterator.notRetrievedYet()), hasItems("Yoda", "Leia"));
+    iterator.next();
+    assertThat(contentsOf(iterator.notRetrievedYet()), hasItems("Leia"));
+    iterator.next();
+    assertTrue(contentsOf(iterator.notRetrievedYet()).isEmpty());
+  }
+
+  private <T> List<T> contentsOf(ExtendedIterator<T> iterator) {
+    return ((ExtendedListIterator<T>) iterator).contents();
+  }
+
+  @Test public void should_indicate_if_last_list_element_was_retrieved() {
+    assertFalse(iterator.wasLastListElementRetrieved());
+    iterator.next(); // Luke
+    assertFalse(iterator.wasLastListElementRetrieved());
+    iterator.next(); // Yoda
+    assertFalse(iterator.wasLastListElementRetrieved());
+    iterator.next(); // Leia
+    assertTrue(iterator.wasLastListElementRetrieved());
+  }
+}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/CppToProtobufMapping.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/CppToProtobufMapping.java
index deffd08..2f94eef 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/CppToProtobufMapping.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/CppToProtobufMapping.java
@@ -18,20 +18,20 @@
  * @author alruiz@google.com (Alex Ruiz)
  */
 public class CppToProtobufMapping {
-  private final List<String> qualifiedNameSegments;
+  private final List<String> qualifiedName;
   private final EClass type;
 
-  CppToProtobufMapping(List<String> qualifiedNameSegments, EClass type) {
-    this.qualifiedNameSegments = qualifiedNameSegments;
+  CppToProtobufMapping(List<String> qualifiedName, EClass type) {
+    this.qualifiedName = qualifiedName;
     this.type = type;
   }
 
   /**
-   * Returns the qualified name segments of the selected C++ element.
-   * @return the qualified name segments of the selected C++ element.
+   * Returns the qualified name of the selected C++ element.
+   * @return the qualified name of the selected C++ element.
    */
-  public List<String> qualifiedNameSegments() {
-    return qualifiedNameSegments;
+  public List<String> qualifiedName() {
+    return qualifiedName;
   }
 
   /**
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/AbstractProtobufElementMatcherStrategy.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/AbstractProtobufElementMatcherStrategy.java
new file mode 100644
index 0000000..845944b
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/AbstractProtobufElementMatcherStrategy.java
@@ -0,0 +1,31 @@
+/*
+ * 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.matching;
+
+import java.util.List;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.*;
+
+import com.google.eclipse.protobuf.cdt.util.ExtendedIterator;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+abstract class AbstractProtobufElementMatcherStrategy {
+  static final String NESTED_ELEMENT_SEPARATOR = "_";
+
+  abstract List<URI> matchingProtobufElementLocations(EObject root, ExtendedIterator<String> qualifiedNameSegments);
+
+  boolean isSupported(EObject o) {
+    return supportedType().equals(o.eClass());
+  }
+
+  abstract EClass supportedType();
+}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/ContentsByType.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/ContentsByType.java
deleted file mode 100644
index fb6cde7..0000000
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/ContentsByType.java
+++ /dev/null
@@ -1,48 +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.matching;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static com.google.common.collect.Maps.newHashMap;
-import static java.util.Collections.*;
-
-import java.util.*;
-
-import org.eclipse.emf.ecore.*;
-
-/**
- * @author alruiz@google.com (Alex Ruiz)
- */
-class ContentsByType {
-  private final Map<EClass, List<EObject>> contentsByType = newHashMap();
-
-  static ContentsByType contentsOf(EObject target) {
-    return new ContentsByType(target);
-  }
-
-  private ContentsByType(EObject target) {
-    for (EObject child : target.eContents()) {
-      EClass type = child.eClass();
-      List<EObject> children = contentsByType.get(type);
-      if (children == null) {
-        children = newArrayList();
-        contentsByType.put(type, children);
-      }
-      children.add(child);
-    }
-  }
-
-  List<EObject> ofType(EClass type) {
-    List<EObject> children = contentsByType.get(type);
-    if (children == null) {
-      return emptyList();
-    }
-    return unmodifiableList(children);
-  }
-}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/MessageMatcherStrategy.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/MessageMatcherStrategy.java
index 0ccd200..c12d6cf 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/MessageMatcherStrategy.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/MessageMatcherStrategy.java
@@ -10,6 +10,7 @@
 
 import static com.google.common.base.Objects.equal;
 import static com.google.common.collect.Lists.newArrayList;
+import static com.google.eclipse.protobuf.cdt.util.ExtendedListIterator.newIterator;
 import static com.google.eclipse.protobuf.protobuf.ProtobufPackage.Literals.MESSAGE;
 import static java.util.Collections.unmodifiableList;
 
@@ -18,6 +19,7 @@
 import org.eclipse.emf.common.util.URI;
 import org.eclipse.emf.ecore.*;
 
+import com.google.eclipse.protobuf.cdt.util.ExtendedIterator;
 import com.google.eclipse.protobuf.model.util.ModelObjects;
 import com.google.eclipse.protobuf.protobuf.Message;
 import com.google.inject.Inject;
@@ -25,67 +27,69 @@
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
-class MessageMatcherStrategy implements ProtobufElementMatcherStrategy {
+class MessageMatcherStrategy extends AbstractProtobufElementMatcherStrategy {
   @Inject private ModelObjects modelObjects;
 
-  @Override public List<URI> matchingProtobufElementLocations(EObject root, List<String> qualifiedName) {
+  @Override public List<URI> matchingProtobufElementLocations(EObject root, ExtendedIterator<String> qualifiedName) {
     List<URI> matches = newArrayList();
-    List<EObject> contents = root.eContents();
-    while (!qualifiedName.isEmpty()) {
-      String segment = qualifiedName.remove(0);
-      for (EObject o : contents) {
+    ExtendedIterator<EObject> contents = newIterator(root.eContents());
+    while (qualifiedName.hasNext()) {
+      String segment = qualifiedName.next();
+      while (contents.hasNext()) {
+        EObject o = contents.next();
         if (!isSupported(o)) {
           continue;
         }
         Message message = (Message) o;
         if (equal(message.getName(), segment)) {
-          if (qualifiedName.isEmpty()) {
+          if (qualifiedName.wasLastListElementRetrieved()) {
             // this is the last segment. This message is a perfect match.
             matches.add(modelObjects.uriOf(message));
           } else {
             // keep looking for match.
-            contents = message.eContents();
+            matches.addAll(matchingProtobufElementLocations(message, qualifiedName.notRetrievedYet()));
           }
-          break;
         }
-        if (segment.contains("_")) {
-          matches.addAll(matchingNestedElementLocations(contents, segment));
-          break;
+        if (segment.contains(NESTED_ELEMENT_SEPARATOR)) {
+          List<Message> matchingNestedElements = matchingNestedElements(message, segment);
+          if (qualifiedName.wasLastListElementRetrieved()) {
+            for (Message m : matchingNestedElements) {
+              matches.add(modelObjects.uriOf(m));
+            }
+          } else {
+            for (Message m : matchingNestedElements) {
+              matches.addAll(matchingProtobufElementLocations(m, qualifiedName.notRetrievedYet()));
+            }
+          }
         }
       }
     }
     return unmodifiableList(matches);
   }
 
-  private List<URI> matchingNestedElementLocations(List<EObject> elements, String nestedQualifiedName) {
-    List<URI> matches = newArrayList();
-    for (EObject o : elements) {
-      if (!isSupported(o)) {
-        continue;
+  private List<Message> matchingNestedElements(Message message, String qualifiedName) {
+    List<Message> matches = newArrayList();
+    String messageName = message.getName();
+    if (qualifiedName.startsWith(messageName)) {
+      String rest = qualifiedName.substring(messageName.length());
+      if (rest.isEmpty()) {
+        matches.add(message);
       }
-      Message message = (Message) o;
-      String messageName = message.getName();
-      if (nestedQualifiedName.startsWith(messageName)) {
-        String rest = nestedQualifiedName.substring(messageName.length());
-        if (rest.isEmpty()) {
-          matches.add(modelObjects.uriOf(message));
+      else {
+        if (rest.startsWith(NESTED_ELEMENT_SEPARATOR)) {
+          rest = rest.substring(1);
         }
-        else {
-          if (rest.startsWith("_")) {
-            rest = rest.substring(1);
+        for (EObject o : message.eContents()) {
+          if (!isSupported(o)) {
+            continue;
           }
-          matches.addAll(matchingNestedElementLocations(message.eContents(), rest));
+          matches.addAll(matchingNestedElements((Message) o, rest));
         }
-        break;
       }
     }
     return matches;
   }
 
-  private boolean isSupported(EObject o) {
-    return supportedType().equals(o.eClass());
-  }
-
   @Override public EClass supportedType() {
     return MESSAGE;
   }
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/PatternBuilder.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/PatternBuilder.java
index 08c6db5..83ea8bc 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/PatternBuilder.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/PatternBuilder.java
@@ -22,7 +22,7 @@
 @Singleton class PatternBuilder {
   Pattern patternToMatchFrom(CppToProtobufMapping mapping) {
     StringBuilder regex = new StringBuilder();
-    List<String> segments = newArrayList(mapping.qualifiedNameSegments());
+    List<String> segments = newArrayList(mapping.qualifiedName());
     int segmentCount = segments.size();
     for (int i = 0; i < segmentCount; i++) {
       String segment = segments.get(i);
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/ProtobufElementMatchFinder.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/ProtobufElementMatchFinder.java
index fbebdee..e37fae4 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/ProtobufElementMatchFinder.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/ProtobufElementMatchFinder.java
@@ -9,6 +9,7 @@
 package com.google.eclipse.protobuf.cdt.matching;
 
 import static com.google.common.collect.Maps.newHashMap;
+import static com.google.eclipse.protobuf.cdt.util.ExtendedListIterator.newIterator;
 import static java.util.Collections.emptyList;
 
 import java.util.*;
@@ -26,7 +27,7 @@
  * @author alruiz@google.com (Alex Ruiz)
  */
 public class ProtobufElementMatchFinder {
-  private final Map<EClass, ProtobufElementMatcherStrategy> strategies = newHashMap();
+  private final Map<EClass, AbstractProtobufElementMatcherStrategy> strategies = newHashMap();
 
   @Inject private Resources resources;
 
@@ -41,10 +42,10 @@
   public List<URI> matchingProtobufElementLocations(Resource resource, CppToProtobufMapping mapping) {
     Protobuf root = resources.rootOf(resource);
     // TODO check for proto2?
-    List<String> qualifiedNameSegments = mapping.qualifiedNameSegments();
-    ProtobufElementMatcherStrategy strategy = strategies.get(mapping.type());
+    List<String> qualifiedName = mapping.qualifiedName();
+    AbstractProtobufElementMatcherStrategy strategy = strategies.get(mapping.type());
     if (strategy != null) {
-      return strategy.matchingProtobufElementLocations(root, qualifiedNameSegments);
+      return strategy.matchingProtobufElementLocations(root, newIterator(qualifiedName));
     }
     return emptyList();
   }
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/ProtobufElementMatcherStrategy.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/ProtobufElementMatcherStrategy.java
deleted file mode 100644
index bc9704d..0000000
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/ProtobufElementMatcherStrategy.java
+++ /dev/null
@@ -1,23 +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.matching;
-
-import java.util.List;
-
-import org.eclipse.emf.common.util.URI;
-import org.eclipse.emf.ecore.*;
-
-/**
- * @author alruiz@google.com (Alex Ruiz)
- */
-interface ProtobufElementMatcherStrategy {
-  List<URI> matchingProtobufElementLocations(EObject root, List<String> qualifiedNameSegments);
-
-  EClass supportedType();
-}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/util/ExtendedIterator.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/util/ExtendedIterator.java
new file mode 100644
index 0000000..e0fc97d
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/util/ExtendedIterator.java
@@ -0,0 +1,38 @@
+/*
+ * 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.util;
+
+import java.util.Iterator;
+
+/**
+ * {@code Iterator} that keeps track of the last retrieved element.
+ * @param <T> the generic type of this {@code Iterator}.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public interface ExtendedIterator<T> extends Iterator<T> {
+
+  /**
+   * Returns the elements that have not been retrieved yet.
+   * @return the elements that have not been retrieved yet.
+   */
+  ExtendedIterator<T> notRetrievedYet();
+
+  /**
+   * Indicates whether the last retrieved element is the last element in the {@code List}.
+   * @return {@code true} if the last retrieved element is the last element in the {@code List}; {@code false} otherwise.
+   */
+  boolean wasLastListElementRetrieved();
+
+  /**
+   * Returns a copy of this {@code Iterator}.
+   * @return a copy of this {@code Iterator}.
+   */
+  ExtendedIterator<T> copy();
+}
\ No newline at end of file
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/util/ExtendedListIterator.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/util/ExtendedListIterator.java
new file mode 100644
index 0000000..b20ca67
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/util/ExtendedListIterator.java
@@ -0,0 +1,94 @@
+/*
+ * 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.util;
+
+import static java.util.Collections.*;
+
+import java.util.List;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.*;
+
+/**
+ * {@code Iterator} for {@code List}s. This implementation keeps track of the index of the current element to be able
+ * to:
+ * <ul>
+ * <li>Retrieve the elements that have not been visited yet</li>
+ * <li>Check whether we are visiting the last element of the {@code List}</li>
+ * @param <T> the generic type of the iterator.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class ExtendedListIterator<T> extends AbstractIterator<T> implements ExtendedIterator<T> {
+  private static final ExtendedIterator<Object> EMPTY = newIterator(emptyList());
+
+  private final List<T> list;
+  private final int listSize;
+
+  private int index = -1;
+
+  /**
+   * Creates a new <code>{@link ExtendedListIterator}</code>.
+   * @param elements the elements of the {@code Iterator} to create.
+   * @return the created {@code ListIterator}.
+   */
+  public static <T> ExtendedIterator<T> newIterator(T...elements) {
+    return new ExtendedListIterator<T>(Lists.newArrayList(elements));
+  }
+
+  /**
+   * Creates a new <code>{@link ExtendedListIterator}</code>.
+   * @param list the {@code List} to iterate.
+   * @return the created {@code ListIterator}.
+   */
+  public static <T> ExtendedIterator<T> newIterator(List<T> list) {
+    return new ExtendedListIterator<T>(list);
+  }
+
+  @VisibleForTesting ExtendedListIterator(List<T> list) {
+    this.list = list;
+    listSize = list.size();
+  }
+
+  /** {@inheritDoc} */
+  @Override @SuppressWarnings("unchecked")
+  public ExtendedIterator<T> notRetrievedYet() {
+    if (listSize == 0) {
+      return (ExtendedIterator<T>) EMPTY;
+    }
+    List<T> remaining = list.subList(index + 1, listSize);
+    return newIterator(remaining);
+  }
+
+  /** {@inheritDoc} */
+  @Override public boolean wasLastListElementRetrieved() {
+    return listSize > 0 && index == listSize - 1;
+  }
+
+  /** {@inheritDoc} */
+  @Override public ExtendedIterator<T> copy() {
+    return new ExtendedListIterator<T>(list);
+  }
+
+  @Override protected T computeNext() {
+    if (index + 1 < listSize && listSize > 0) {
+      return list.get(++index);
+    }
+    return endOfData();
+  }
+
+  @Override public String toString() {
+    return list.toString();
+  }
+
+  @VisibleForTesting List<T> contents() {
+    return unmodifiableList(list);
+  }
+
+}