In progress: [Issue 199] Add ability to navigate to proto element from
generated C++ code.
* Made navigation from C++ class to message definition 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 c35c9a5..bbf3a63 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
@@ -8,21 +8,21 @@
*/
package com.google.eclipse.protobuf.cdt.mapping;
-import static com.google.common.collect.ImmutableList.copyOf;
+import static com.google.common.collect.Lists.newArrayList;
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.protobuf.ProtobufPackage.Literals.MESSAGE;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.*;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
import org.eclipse.cdt.core.dom.ast.IBinding;
-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.cdt.internal.core.dom.parser.cpp.CPPClassType;
import org.junit.*;
import com.google.eclipse.protobuf.junit.core.*;
-import com.google.eclipse.protobuf.protobuf.Message;
import com.google.inject.Inject;
/**
@@ -34,41 +34,28 @@
public class ClassMappingStrategy_createMappingFrom_Test {
@Rule public XtextRule xtext = overrideRuntimeModuleWith(unitTestModule(), new TestModule());
+ @Inject private IBindings bindings;
@Inject private CPPClassType classType;
@Inject private ClassMappingStrategy mappingStrategy;
- @Test public void should_return_qualified_name_for_class_type_if_it_extends_proto_file() {
- expectClassTypeToExtendProtoMessage();
- String[] segments = { "com", "google", "proto", "Test" };
- when(classType.getQualifiedName()).thenReturn(segments);
+ @Test public void should_create_mapping_if_class_type_is_message() {
+ when(bindings.isMessage(classType)).thenReturn(true);
+ List<String> segments = newArrayList("com", "google", "proto", "Test");
+ when(bindings.qualifiedNameOf(classType)).thenReturn(segments);
CppToProtobufMapping mapping = mappingStrategy.createMappingFrom(classType);
- assertThat(mapping.qualifiedNameSegments(), equalTo(copyOf(segments)));
- assertEquals(Message.class, mapping.type());
+ assertThat(mapping.qualifiedNameSegments(), equalTo(segments));
+ assertThat(mapping.type(), equalTo(MESSAGE));
}
- 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;
- }
-
- @Test public void should_return_null_if_class_type_does_not_extend_proto_message() {
- when(classType.getBases()).thenReturn(new ICPPBase[0]);
+ @Test public void should_return_null_if_class_type_is_not_message() {
+ when(bindings.isMessage(classType)).thenReturn(false);
CppToProtobufMapping mapping = mappingStrategy.createMappingFrom(classType);
assertNull(mapping);
}
private static class TestModule extends AbstractTestModule {
@Override protected void configure() {
+ mockAndBind(IBindings.class);
mockAndBind(CPPClassType.class);
}
}
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
new file mode 100644
index 0000000..da9064d
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/MessageMatcherStrategy_matchingProtobufElementLocations_Test.java
@@ -0,0 +1,93 @@
+/*
+ * 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.eclipse.protobuf.cdt.matching.URIsReferToEObjects.referTo;
+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.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.junit.*;
+
+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>
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class MessageMatcherStrategy_matchingProtobufElementLocations_Test {
+ @Rule public XtextRule xtext = overrideRuntimeModuleWith(unitTestModule());
+
+ @Inject private MessageMatcherStrategy matcher;
+
+ // syntax = "proto2";
+ //
+ // message Person {}
+ //
+ // 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));
+ }
+
+ // syntax = "proto2";
+ //
+ // message Person {
+ // 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));
+ }
+
+ // syntax = "proto2";
+ //
+ // message Person {
+ // message Address {
+ // message Type {}
+ // }
+ // }
+ @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));
+ }
+
+ // syntax = "proto2";
+ //
+ // message Person_Address {
+ // 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));
+ }
+
+ // syntax = "proto2";
+ //
+ // message Person {
+ // 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));
+ }
+}
diff --git a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/PatternBuilder_patternToMatchFrom_Test.java b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/PatternBuilder_patternToMatchFrom_Test.java
deleted file mode 100644
index f1ccfd0..0000000
--- a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/PatternBuilder_patternToMatchFrom_Test.java
+++ /dev/null
@@ -1,54 +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.eclipse.protobuf.cdt.matching.PatternMatcher.matches;
-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.protobuf.ProtobufPackage.Literals.MESSAGE;
-import static org.hamcrest.core.IsEqual.equalTo;
-import static org.junit.Assert.assertThat;
-
-import java.util.regex.Pattern;
-
-import org.junit.*;
-
-import com.google.eclipse.protobuf.cdt.mapping.CppToProtobufMapping;
-import com.google.eclipse.protobuf.junit.core.XtextRule;
-import com.google.inject.Inject;
-
-/**
- * Tests for <code>{@link PatternBuilder#patternToMatchFrom(CppToProtobufMapping)}</code>
- *
- * @author alruiz@google.com (Alex Ruiz)
- */
-public class PatternBuilder_patternToMatchFrom_Test {
- @Rule public XtextRule xtext = overrideRuntimeModuleWith(unitTestModule());
-
- @Inject private PatternBuilder builder;
-
- @Test public void should_escape_dots() {
- CppToProtobufMapping mapping = createMessageMapping("com", "google", "proto", "test", "Person");
- Pattern pattern = builder.patternToMatchFrom(mapping);
- assertThat(pattern.pattern(), equalTo("com\\.google\\.proto\\.test\\.Person"));
- assertThat("com.google.proto.test.Person", matches(pattern));
- }
-
- @Test public void should_escape_underscore() {
- CppToProtobufMapping mapping = createMessageMapping("com", "google", "proto", "test", "Person_PhoneType");
- Pattern pattern = builder.patternToMatchFrom(mapping);
- assertThat(pattern.pattern(), equalTo("com\\.google\\.proto\\.test\\.Person(\\.|_)PhoneType"));
- assertThat("com.google.proto.test.Person.PhoneType", matches(pattern));
- assertThat("com.google.proto.test.Person_PhoneType", matches(pattern));
- }
-
- private CppToProtobufMapping createMessageMapping(String... qualifiedNameSegments) {
- return new CppToProtobufMapping(qualifiedNameSegments, MESSAGE);
- }
-}
diff --git a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/PatternMatcher.java b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/PatternMatcher.java
deleted file mode 100644
index c7d4f07..0000000
--- a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/PatternMatcher.java
+++ /dev/null
@@ -1,38 +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.regex.Pattern;
-
-import org.hamcrest.*;
-
-/**
- * @author alruiz@google.com (Alex Ruiz)
- */
-class PatternMatcher extends TypeSafeMatcher<String> {
- private final Pattern pattern;
-
- static PatternMatcher matches(Pattern pattern) {
- return new PatternMatcher(pattern);
- }
-
- private PatternMatcher(Pattern pattern) {
- super(String.class);
- this.pattern = pattern;
- }
-
- @Override public boolean matchesSafely(String item) {
- return pattern.matcher(item).matches();
- }
-
- @Override public void describeTo(Description description) {
- description.appendValue(pattern.pattern());
- }
-
-}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/ClassMappingStrategy.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/ClassMappingStrategy.java
index 9e87acf..ecd7349 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/ClassMappingStrategy.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/ClassMappingStrategy.java
@@ -20,12 +20,12 @@
*/
@SuppressWarnings("restriction")
class ClassMappingStrategy implements IBindingMappingStrategy<CPPClassType> {
- @Inject private AstElements astElements;
+ @Inject private IBindings bindings;
@Override public CppToProtobufMapping createMappingFrom(IBinding binding) {
CPPClassType classType = typeOfSupportedBinding().cast(binding);
- if (astElements.isMessage(classType)) {
- return new CppToProtobufMapping(classType.getQualifiedName(), MESSAGE);
+ if (bindings.isMessage(classType)) {
+ return new CppToProtobufMapping(bindings.qualifiedNameOf(classType), MESSAGE);
}
return null;
}
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 9422974..deffd08 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
@@ -8,23 +8,21 @@
*/
package com.google.eclipse.protobuf.cdt.mapping;
-import static com.google.common.collect.ImmutableList.copyOf;
+import java.util.List;
import org.eclipse.emf.ecore.EClass;
-import com.google.common.collect.ImmutableList;
-
/**
* Information of the protocol buffer element obtained from a generated C++ element.
*
* @author alruiz@google.com (Alex Ruiz)
*/
public class CppToProtobufMapping {
- private final ImmutableList<String> qualifiedNameSegments;
+ private final List<String> qualifiedNameSegments;
private final EClass type;
- public CppToProtobufMapping(String[] qualifiedNameSegments, EClass type) {
- this.qualifiedNameSegments = copyOf(qualifiedNameSegments);
+ CppToProtobufMapping(List<String> qualifiedNameSegments, EClass type) {
+ this.qualifiedNameSegments = qualifiedNameSegments;
this.type = type;
}
@@ -32,7 +30,7 @@
* Returns the qualified name segments of the selected C++ element.
* @return the qualified name segments of the selected C++ element.
*/
- public ImmutableList<String> qualifiedNameSegments() {
+ public List<String> qualifiedNameSegments() {
return qualifiedNameSegments;
}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/EnumMappingStrategy.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/EnumMappingStrategy.java
index c2db20c..aac7eb8 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/EnumMappingStrategy.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/EnumMappingStrategy.java
@@ -13,15 +13,18 @@
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPEnumeration;
+import com.google.inject.Inject;
+
/**
* @author alruiz@google.com (Alex Ruiz)
*/
@SuppressWarnings("restriction")
class EnumMappingStrategy implements IBindingMappingStrategy<CPPEnumeration> {
+ @Inject private IBindings bindings;
@Override public CppToProtobufMapping createMappingFrom(IBinding binding) {
CPPEnumeration enumeration = typeOfSupportedBinding().cast(binding);
- return new CppToProtobufMapping(enumeration.getQualifiedName(), ENUM);
+ return new CppToProtobufMapping(bindings.qualifiedNameOf(enumeration), ENUM);
}
@Override public Class<CPPEnumeration> typeOfSupportedBinding() {
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/AstElements.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/IBindings.java
similarity index 64%
rename from com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/AstElements.java
rename to com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/IBindings.java
index 3dc7e4a..21e1b7a 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/AstElements.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/IBindings.java
@@ -9,10 +9,14 @@
package com.google.eclipse.protobuf.cdt.mapping;
import static com.google.common.collect.ImmutableList.of;
+import static com.google.common.collect.Lists.newArrayList;
+import static java.util.Collections.unmodifiableList;
+
+import java.util.List;
import org.eclipse.cdt.core.dom.IName;
import org.eclipse.cdt.core.dom.ast.IBinding;
-import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
+import org.eclipse.cdt.core.dom.ast.cpp.*;
import org.eclipse.cdt.internal.core.dom.parser.cpp.*;
import com.google.common.collect.ImmutableList;
@@ -21,7 +25,7 @@
* @author alruiz@google.com (Alex Ruiz)
*/
@SuppressWarnings("restriction")
-class AstElements {
+class IBindings {
private static final ImmutableList<String> MESSAGE_SUPER_TYPES = of("::google::protobuf::Message",
"google::protobuf::MessageLite");
@@ -45,4 +49,23 @@
String qualifiedNameAsText = qualifiedName.toString();
return MESSAGE_SUPER_TYPES.contains(qualifiedNameAsText);
}
+
+ List<String> qualifiedNameOf(IBinding binding) {
+ List<String> segments = newArrayList();
+ for (IBinding owner = binding.getOwner(); owner != null; owner = owner.getOwner()) {
+ if (owner instanceof ICPPEnumeration && !((ICPPEnumeration) owner).isScoped()) {
+ continue;
+ }
+ String ownerName = owner.getName();
+ if (ownerName == null) {
+ break;
+ }
+ if (owner instanceof ICPPFunction || owner instanceof ICPPNamespace) {
+ continue;
+ }
+ segments.add(0, ownerName);
+ }
+ segments.add(binding.getName());
+ return unmodifiableList(segments);
+ }
}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/MethodMappingStrategy.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/MethodMappingStrategy.java
index dcef34a..fb3caba 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/MethodMappingStrategy.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/MethodMappingStrategy.java
@@ -14,11 +14,14 @@
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethod;
+import com.google.inject.Inject;
+
/**
* @author alruiz@google.com (Alex Ruiz)
*/
@SuppressWarnings("restriction")
class MethodMappingStrategy implements IBindingMappingStrategy<CPPMethod> {
+ @Inject private IBindings bindings;
@Override public CppToProtobufMapping createMappingFrom(IBinding binding) {
CPPMethod method = typeOfSupportedBinding().cast(binding);
@@ -30,7 +33,7 @@
if (types != null && types.length > 0) {
return null;
}
- return new CppToProtobufMapping(method.getQualifiedName(), MESSAGE_FIELD);
+ return new CppToProtobufMapping(bindings.qualifiedNameOf(method), MESSAGE_FIELD);
}
@Override public Class<CPPMethod> typeOfSupportedBinding() {
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/TypeDefMappingStrategy.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/TypeDefMappingStrategy.java
index 88fca85..0b5b4e7 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/TypeDefMappingStrategy.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/TypeDefMappingStrategy.java
@@ -20,12 +20,12 @@
*/
@SuppressWarnings("restriction")
class TypeDefMappingStrategy implements IBindingMappingStrategy<CPPTypedef> {
- @Inject private AstElements astElements;
+ @Inject private IBindings bindings;
@Override public CppToProtobufMapping createMappingFrom(IBinding binding) {
CPPTypedef typeDef = typeOfSupportedBinding().cast(binding);
IBinding owner = binding.getOwner();
- if (!astElements.isMessage(owner)) {
+ if (!bindings.isMessage(owner)) {
return null;
}
String typeName = typeNameOf(typeDef);
@@ -33,7 +33,7 @@
if (typeName == null || !typeName.endsWith(typeNameSuffix)) {
return null;
}
- return new CppToProtobufMapping(typeDef.getQualifiedName(), MESSAGE);
+ return new CppToProtobufMapping(bindings.qualifiedNameOf(typeDef), MESSAGE);
}
private String typeNameOf(CPPTypedef typeDef) {
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 1f9fe3c..0ccd200 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
@@ -8,8 +8,8 @@
*/
package com.google.eclipse.protobuf.cdt.matching;
+import static com.google.common.base.Objects.equal;
import static com.google.common.collect.Lists.newArrayList;
-import static com.google.eclipse.protobuf.cdt.matching.ContentsByType.contentsOf;
import static com.google.eclipse.protobuf.protobuf.ProtobufPackage.Literals.MESSAGE;
import static java.util.Collections.unmodifiableList;
@@ -17,48 +17,73 @@
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.*;
-import org.eclipse.emf.ecore.resource.Resource;
+import com.google.eclipse.protobuf.model.util.ModelObjects;
import com.google.eclipse.protobuf.protobuf.Message;
+import com.google.inject.Inject;
/**
* @author alruiz@google.com (Alex Ruiz)
*/
class MessageMatcherStrategy implements ProtobufElementMatcherStrategy {
- @Override public List<URI> matchingProtobufElementLocations(ContentsByType contents, String[] qualifiedNameSegments) {
+ @Inject private ModelObjects modelObjects;
+
+ @Override public List<URI> matchingProtobufElementLocations(EObject root, List<String> qualifiedName) {
List<URI> matches = newArrayList();
- int segmentCount = qualifiedNameSegments.length;
- for (int i = 0; i < segmentCount; i++) {
- String segment = qualifiedNameSegments[i];
- for (EObject e : contents.ofType(supportedType())) {
- if (!(e instanceof Message)) {
+ List<EObject> contents = root.eContents();
+ while (!qualifiedName.isEmpty()) {
+ String segment = qualifiedName.remove(0);
+ for (EObject o : contents) {
+ if (!isSupported(o)) {
continue;
}
- Message message = (Message) e;
- if (segment.equals(message.getName())) {
- if (i == segmentCount - 1) {
- // we found what we were looking for.
- matches.add(uriOf(message));
- break;
+ Message message = (Message) o;
+ if (equal(message.getName(), segment)) {
+ if (qualifiedName.isEmpty()) {
+ // this is the last segment. This message is a perfect match.
+ matches.add(modelObjects.uriOf(message));
+ } else {
+ // keep looking for match.
+ contents = message.eContents();
}
- // perfect segment match - go one level deeper.
- contents = contentsOf(message);
- continue;
+ break;
}
if (segment.contains("_")) {
-
+ matches.addAll(matchingNestedElementLocations(contents, segment));
+ break;
}
}
}
return unmodifiableList(matches);
}
- // TODO move to ModelObjects
- private URI uriOf(EObject e) {
- Resource resource = e.eResource();
- URI uri = resource.getURI();
- uri = uri.appendFragment(resource.getURIFragment(e));
- return uri;
+ private List<URI> matchingNestedElementLocations(List<EObject> elements, String nestedQualifiedName) {
+ List<URI> matches = newArrayList();
+ for (EObject o : elements) {
+ if (!isSupported(o)) {
+ continue;
+ }
+ 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("_")) {
+ rest = rest.substring(1);
+ }
+ matches.addAll(matchingNestedElementLocations(message.eContents(), rest));
+ }
+ break;
+ }
+ }
+ return matches;
+ }
+
+ private boolean isSupported(EObject o) {
+ return supportedType().equals(o.eClass());
}
@Override public EClass supportedType() {
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 cfd9596..fbebdee 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
@@ -8,23 +8,18 @@
*/
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 com.google.eclipse.protobuf.cdt.matching.ContentsByType.contentsOf;
-import static com.google.eclipse.protobuf.protobuf.ProtobufPackage.Literals.PACKAGE;
import static java.util.Collections.emptyList;
import java.util.*;
import org.eclipse.emf.common.util.URI;
-import org.eclipse.emf.ecore.*;
+import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.resource.Resource;
import com.google.eclipse.protobuf.cdt.mapping.CppToProtobufMapping;
-import com.google.eclipse.protobuf.model.util.*;
-import com.google.eclipse.protobuf.protobuf.*;
-import com.google.eclipse.protobuf.protobuf.Package;
-import com.google.eclipse.protobuf.util.StringLists;
+import com.google.eclipse.protobuf.model.util.Resources;
+import com.google.eclipse.protobuf.protobuf.Protobuf;
import com.google.inject.Inject;
/**
@@ -33,9 +28,7 @@
public class ProtobufElementMatchFinder {
private final Map<EClass, ProtobufElementMatcherStrategy> strategies = newHashMap();
- @Inject private Packages packages;
@Inject private Resources resources;
- @Inject private StringLists stringLists;
@Inject public ProtobufElementMatchFinder(MessageMatcherStrategy s1) {
register(s1);
@@ -48,35 +41,12 @@
public List<URI> matchingProtobufElementLocations(Resource resource, CppToProtobufMapping mapping) {
Protobuf root = resources.rootOf(resource);
// TODO check for proto2?
- ContentsByType contents = contentsOf(root);
- String[] qualifiedNameSegments = removePackageFromQualifiedName(mapping.qualifiedNameSegments(), contents);
+ List<String> qualifiedNameSegments = mapping.qualifiedNameSegments();
ProtobufElementMatcherStrategy strategy = strategies.get(mapping.type());
if (strategy != null) {
- return strategy.matchingProtobufElementLocations(contents, qualifiedNameSegments);
+ return strategy.matchingProtobufElementLocations(root, qualifiedNameSegments);
}
return emptyList();
}
- private String[] removePackageFromQualifiedName(List<String> qualifiedNameSegments, ContentsByType contents) {
- Package aPackage = packageFrom(contents);
- if (aPackage != null) {
- return stringLists.toArray(qualifiedNameSegments);
- }
- List<String> segments = newArrayList(qualifiedNameSegments);
- for (String packageSegment : packages.segmentsOf(aPackage)) {
- if (segments.isEmpty() || !packageSegment.equals(segments.get(0))) {
- break;
- }
- segments.remove(0);
- }
- return stringLists.toArray(segments);
- }
-
- private Package packageFrom(ContentsByType contents) {
- List<EObject> packages = contents.ofType(PACKAGE);
- if (packages.isEmpty()) {
- return null;
- }
- return (Package) packages.get(0);
- }
}
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
index b4cb9e2..bc9704d 100644
--- 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
@@ -11,13 +11,13 @@
import java.util.List;
import org.eclipse.emf.common.util.URI;
-import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.*;
/**
* @author alruiz@google.com (Alex Ruiz)
*/
interface ProtobufElementMatcherStrategy {
- List<URI> matchingProtobufElementLocations(ContentsByType contents, String[] qualifiedNameSegments);
+ List<URI> matchingProtobufElementLocations(EObject root, List<String> qualifiedNameSegments);
EClass supportedType();
}
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/model/util/ModelObjects_uriOf_Test.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/model/util/ModelObjects_uriOf_Test.java
new file mode 100644
index 0000000..d607de5
--- /dev/null
+++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/model/util/ModelObjects_uriOf_Test.java
@@ -0,0 +1,43 @@
+/*
+ * 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.model.util;
+
+import static com.google.eclipse.protobuf.junit.core.UnitTestModule.unitTestModule;
+import static com.google.eclipse.protobuf.junit.core.XtextRule.overrideRuntimeModuleWith;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.junit.*;
+
+import com.google.eclipse.protobuf.junit.core.XtextRule;
+import com.google.eclipse.protobuf.protobuf.Message;
+import com.google.inject.Inject;
+
+/**
+ * Tests for <code>{@link ModelObjects#uriOf(EObject)}</code>
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class ModelObjects_uriOf_Test {
+ @Rule public XtextRule xtext = overrideRuntimeModuleWith(unitTestModule());
+
+ @Inject private ModelObjects objects;
+
+ // syntax = "proto2";
+ //
+ // message Person {}
+ @Test public void should_return_uri_of_model_object() {
+ Message message = xtext.find("Person", Message.class);
+ URI expected = xtext.resource().getURI();
+ expected = expected.appendFragment(xtext.resource().getURIFragment(message));
+ assertThat(objects.uriOf(message), equalTo(expected));
+ }
+}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/ModelObjects.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/ModelObjects.java
index 6ec9da1..7aa3d9f 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/ModelObjects.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/ModelObjects.java
@@ -8,7 +8,9 @@
*/
package com.google.eclipse.protobuf.model.util;
+import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.*;
+import org.eclipse.emf.ecore.resource.Resource;
import com.google.eclipse.protobuf.protobuf.*;
import com.google.eclipse.protobuf.protobuf.Package;
@@ -67,4 +69,15 @@
}
return (Protobuf) current;
}
+
+ /**
+ * Returns the URI of the given model element.
+ * @param e the given model element.
+ * @return the URI of the given model element.
+ */
+ public URI uriOf(EObject e) {
+ Resource resource = e.eResource();
+ URI uri = resource.getURI();
+ return uri.appendFragment(resource.getURIFragment(e));
+ }
}