In progress: [ Issue 24 ] Fix qualified names
https://code.google.com/p/protobuf-dt/issues/detail?id=24
Qualified names for types in the same message as the type reference are now successfully created.
diff --git a/com.google.eclipse.protobuf.junit/src/com/google/eclipse/protobuf/junit/util/Finder.java b/com.google.eclipse.protobuf.junit/src/com/google/eclipse/protobuf/junit/util/Finder.java
index 0d2decf..31583dc 100644
--- a/com.google.eclipse.protobuf.junit/src/com/google/eclipse/protobuf/junit/util/Finder.java
+++ b/com.google.eclipse.protobuf.junit/src/com/google/eclipse/protobuf/junit/util/Finder.java
@@ -13,12 +13,19 @@
import java.util.List;
import com.google.eclipse.protobuf.protobuf.*;
+import com.google.eclipse.protobuf.protobuf.Enum;
/**
* @author alruiz@google.com (Alex Ruiz)
*/
public final class Finder {
+ public static Enum findEnum(String name, Protobuf root) {
+ for (Enum anEnum : getAllContentsOfType(root, Enum.class))
+ if (name.equals(anEnum.getName())) return anEnum;
+ return null;
+ }
+
public static Message findMessage(String name, Protobuf root) {
for (Message message : getAllContentsOfType(root, Message.class))
if (name.equals(message.getName())) return message;
@@ -36,17 +43,17 @@
if (name.equals(property.getName())) return property;
return null;
}
-
+
public static List<Property> allProperties(Protobuf root) {
return getAllContentsOfType(root, Property.class);
}
-
+
public static Literal findLiteral(String name, Protobuf root) {
List<Literal> literals = getAllContentsOfType(root, Literal.class);
for (Literal literal : literals)
if (name.equals(literal.getName())) return literal;
return null;
}
-
+
private Finder() {}
}
diff --git a/com.google.eclipse.protobuf.test/.settings/org.eclipse.jdt.core.prefs b/com.google.eclipse.protobuf.test/.settings/org.eclipse.jdt.core.prefs
index f6d1a9a..d8e674c 100644
--- a/com.google.eclipse.protobuf.test/.settings/org.eclipse.jdt.core.prefs
+++ b/com.google.eclipse.protobuf.test/.settings/org.eclipse.jdt.core.prefs
@@ -1,8 +1,12 @@
-#Mon Apr 25 12:58:25 PDT 2011
+#Thu May 05 01:10:30 PDT 2011
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.5
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/AlternativeQualifiedNamesProvider_alternativeFullyQualifiedNames_Test.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/AlternativeQualifiedNamesProvider_alternativeFullyQualifiedNames_Test.java
new file mode 100644
index 0000000..45f0b4d
--- /dev/null
+++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/AlternativeQualifiedNamesProvider_alternativeFullyQualifiedNames_Test.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.scoping;
+
+import static com.google.eclipse.protobuf.junit.util.Finder.findEnum;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+import java.util.List;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.naming.QualifiedName;
+import org.junit.*;
+
+import com.google.eclipse.protobuf.junit.core.XtextRule;
+import com.google.eclipse.protobuf.protobuf.*;
+import com.google.eclipse.protobuf.protobuf.Enum;
+
+/**
+ * Tests for <code>{@link AlternativeQualifiedNamesProvider#alternativeFullyQualifiedNames(EObject)}</code>.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class AlternativeQualifiedNamesProvider_alternativeFullyQualifiedNames_Test {
+
+ @Rule public XtextRule xtext = new XtextRule();
+
+ private AlternativeQualifiedNamesProvider namesProvider;
+
+ @Before public void setUp() {
+ namesProvider = xtext.getInstanceOf(AlternativeQualifiedNamesProvider.class);
+ }
+
+ @Test public void should_return_all_possible_qualified_names() {
+ StringBuilder proto = new StringBuilder();
+ proto.append("package alternative.names; ");
+ proto.append(" ");
+ proto.append("message Person { ");
+ proto.append(" message PhoneNumber { ");
+ proto.append(" optional PhoneType type = 1 [default = HOME];");
+ proto.append(" ");
+ proto.append(" enum PhoneType { ");
+ proto.append(" HOME = 0; ");
+ proto.append(" WORK = 1; ");
+ proto.append(" } ");
+ proto.append(" } ");
+ proto.append("} ");
+ Protobuf root = xtext.parse(proto);
+ Enum phoneType = findEnum("PhoneType", root);
+ List<QualifiedName> names = namesProvider.alternativeFullyQualifiedNames(phoneType);
+ assertThat(names.get(0).toString(), equalTo("PhoneType"));
+ assertThat(names.get(1).toString(), equalTo("PhoneNumber.PhoneType"));
+ assertThat(names.get(2).toString(), equalTo("Person.PhoneNumber.PhoneType"));
+ }
+}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/AlternativeQualifiedNamesProvider.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/AlternativeQualifiedNamesProvider.java
new file mode 100644
index 0000000..fbb35d6
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/AlternativeQualifiedNamesProvider.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.scoping;
+
+import static org.eclipse.xtext.util.SimpleAttributeResolver.newResolver;
+import static org.eclipse.xtext.util.Strings.isEmpty;
+import static org.eclipse.xtext.util.Tuples.pair;
+
+import java.util.*;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.naming.*;
+import org.eclipse.xtext.util.*;
+
+import com.google.common.base.Function;
+import com.google.inject.*;
+
+/**
+ * Provides alternative qualified names for protobuf elements.
+ * <p>
+ * For example, given the following proto element:
+ * <pre>
+ * package alternative.names;
+ *
+ * message Person {
+ * optional string name = 1;
+ *
+ * enum PhoneType {
+ * HOME = 0;
+ * WORK = 1;
+ * }
+ * }
+ * </pre>
+ * The default qualified name for {@code PhoneType} is {@code alternative.names.Person.PhoneType}. The problem is that
+ * protoc also recognizes the following as qualified names:
+ * <ul>
+ * <li>{@code PhoneType}</li>
+ * <li>{@code Person.PhoneType}</li>
+ * </ul>
+ * </p>
+ * <p>
+ * This class provides the non-default qualified names recognized by protoc.
+ * </p>
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class AlternativeQualifiedNamesProvider {
+
+ // TODO: in example above, it looks like protoc considers names.Person.PhoneType as valid. In short, qualified
+ // names can use segments of the package as well.
+
+ @Inject private final IQualifiedNameConverter converter = new IQualifiedNameConverter.DefaultImpl();
+ @Inject private final IResourceScopeCache cache = IResourceScopeCache.NullImpl.INSTANCE;
+
+ private final Function<EObject, String> resolver = newResolver(String.class, "name");
+
+ List<QualifiedName> alternativeFullyQualifiedNames(final EObject obj) {
+ Pair<EObject, String> key = pair(obj, "fqns");
+ return cache.get(key, obj.eResource(), new Provider<List<QualifiedName>>() {
+ public List<QualifiedName> get() {
+ List<QualifiedName> names = new ArrayList<QualifiedName>();
+ EObject current = obj;
+ String name = resolver.apply(current);
+ if (isEmpty(name)) return names;
+ QualifiedName qualifiedName = converter.toQualifiedName(name);
+ names.add(qualifiedName);
+ while (current.eContainer() != null) {
+ current = current.eContainer();
+ String containerName = resolver.apply(current);
+ if (isEmpty(containerName)) continue;
+ qualifiedName = converter.toQualifiedName(containerName).append(qualifiedName);
+ names.add(qualifiedName);
+ }
+ return names;
+ }
+ });
+ }
+}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java
index 0275d65..e02d65d 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java
@@ -10,26 +10,21 @@
import static org.eclipse.emf.common.util.URI.createURI;
import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents;
+import static org.eclipse.xtext.EcoreUtil2.getAllContentsOfType;
import static org.eclipse.xtext.resource.EObjectDescription.create;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
-import org.eclipse.emf.common.util.TreeIterator;
-import org.eclipse.emf.common.util.URI;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.EReference;
-import org.eclipse.emf.ecore.resource.Resource;
-import org.eclipse.emf.ecore.resource.ResourceSet;
-import org.eclipse.xtext.naming.IQualifiedNameProvider;
-import org.eclipse.xtext.naming.QualifiedName;
+import org.eclipse.emf.common.util.*;
+import org.eclipse.emf.ecore.*;
+import org.eclipse.emf.ecore.resource.*;
+import org.eclipse.xtext.naming.*;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.impl.*;
import com.google.eclipse.protobuf.protobuf.*;
import com.google.eclipse.protobuf.protobuf.Enum;
-import com.google.eclipse.protobuf.protobuf.Package;
import com.google.eclipse.protobuf.util.ProtobufElementFinder;
import com.google.inject.Inject;
@@ -48,43 +43,29 @@
@Inject private Globals globals;
@Inject private IQualifiedNameProvider nameProvider;
@Inject private ImportUriResolver uriResolver;
-
+ @Inject private AlternativeQualifiedNamesProvider alternativeNamesProvider;
+
@SuppressWarnings("unused")
IScope scope_TypeReference_type(TypeReference typeRef, EReference reference) {
Protobuf root = finder.rootOf(typeRef);
List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
Message message = (Message) typeRef.eContainer().eContainer();
- addAllTypeDescriptionsInsideRoot(message, descriptions);
+ descriptions.addAll(allTypeDescriptionsInside(message));
descriptions.addAll(importedTypes(root));
- return createScope(descriptions);
+ IScope scope = createScope(descriptions);
+ System.out.println("scope for property: " + ((Property) typeRef.eContainer()).getName() + ": " + scope);
+ return scope;
}
- private void addAllTypeDescriptionsInsideRoot(Message root, List<IEObjectDescription> descriptions) {
- TreeIterator<EObject> allContents = root.eAllContents();
- while (allContents.hasNext()) {
- EObject element = allContents.next();
- if (!(element instanceof Type)) continue;
- Type type = (Type) element;
- descriptions.addAll(describeUsingQualifiedNames(type));
- descriptions.add(create(type.getName(), type));
- }
- }
-
- private List<IEObjectDescription> describeUsingQualifiedNames(Type type) {
+ private List<IEObjectDescription> allTypeDescriptionsInside(Message root) {
List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
- QualifiedName fqn = nameProvider.getFullyQualifiedName(type);
- descriptions.add(create(fqn, type));
- QualifiedName fqnWithoutPackage = removePackage(fqn, type);
- if (fqnWithoutPackage != null) descriptions.add(create(fqnWithoutPackage, type));
+ for (Type type : getAllContentsOfType(root, Type.class)) {
+ for (QualifiedName name : alternativeNamesProvider.alternativeFullyQualifiedNames(type))
+ descriptions.add(create(name, type));
+ }
return descriptions;
}
- private QualifiedName removePackage(QualifiedName fqn, Type type) {
- Package aPackage = finder.packageOf(type);
- if (aPackage == null) return null;
- return null;
- }
-
private List<IEObjectDescription> importedTypes(Protobuf root) {
ResourceSet resourceSet = root.eResource().getResourceSet();
List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
@@ -107,7 +88,7 @@
}
return descriptions;
}
-
+
@SuppressWarnings("unused")
IScope scope_LiteralRef_literal(LiteralRef literalRef, EReference reference) {
EObject container = literalRef.eContainer();