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);
+ }
+
+}