Fixed: [ Issue 24 ] Fix qualified names
https://code.google.com/p/protobuf-dt/issues/detail?id=24
I think I got this right now. Also cleaned up the implementation of ProtobufScopeProvider.
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/contentassist/ProtobufProposalProvider.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/contentassist/ProtobufProposalProvider.java
index 56e47d8..f3efcd9 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/contentassist/ProtobufProposalProvider.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/contentassist/ProtobufProposalProvider.java
@@ -242,7 +242,7 @@
}
private boolean isStringProperty(Property p) {
- return STRING.equals(finder.scalarTypeOfProperty(p));
+ return STRING.equals(finder.scalarTypeOf(p));
}
@Override public void completeLiteral_Index(EObject model, Assignment assignment, ContentAssistContext context,
@@ -253,7 +253,7 @@
@Override public void completeProperty_Default(EObject model, Assignment assignment, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
- Enum enumType = finder.enumTypeOfProperty((Property) model);
+ Enum enumType = finder.enumTypeOf((Property) model);
if (enumType == null) return;
proposeAndAccept(enumType, context, acceptor);
}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/ProtobufQualifiedNameProvider.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/ProtobufQualifiedNameProvider.java
index a45f1bb..42c6f3c 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/ProtobufQualifiedNameProvider.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/ProtobufQualifiedNameProvider.java
@@ -8,49 +8,65 @@
*/
package com.google.eclipse.protobuf.naming;
-import java.util.*;
+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 org.eclipse.emf.ecore.EObject;
-import org.eclipse.xtext.naming.*;
+import org.eclipse.xtext.naming.IQualifiedNameConverter;
+import org.eclipse.xtext.naming.IQualifiedNameProvider;
+import org.eclipse.xtext.naming.QualifiedName;
+import org.eclipse.xtext.util.IResourceScopeCache;
+import org.eclipse.xtext.util.Pair;
+import com.google.common.base.Function;
import com.google.eclipse.protobuf.protobuf.Package;
import com.google.eclipse.protobuf.util.EObjectFinder;
import com.google.inject.Inject;
+import com.google.inject.Provider;
/**
* Provides fully-qualified names for protobuf elements.
- *
+ *
* @author alruiz@google.com (Alex Ruiz)
*/
-public class ProtobufQualifiedNameProvider extends DefaultDeclarativeQualifiedNameProvider {
+public class ProtobufQualifiedNameProvider extends IQualifiedNameProvider.AbstractImpl {
+
+ @Inject private IQualifiedNameConverter converter = new IQualifiedNameConverter.DefaultImpl();
+ @Inject private IResourceScopeCache cache = IResourceScopeCache.NullImpl.INSTANCE;
@Inject private EObjectFinder finder;
+
+ private Function<EObject, String> resolver = newResolver(String.class, "name");
- /** {@inheritDoc} */
- @Override public QualifiedName getFullyQualifiedName(EObject obj) {
- QualifiedName qualifiedName = super.getFullyQualifiedName(obj);
- if (qualifiedName == null || obj instanceof Package) return qualifiedName;
- Package p = finder.findPackage(obj);
- if (p == null) return qualifiedName;
- List<String> newQualifiedNameSegments = new ArrayList<String>();
- List<String> qualifiedNameSegments = qualifiedName.getSegments();
- String packageName = p.getName();
- if (packageName != null) {
- String[] packageNameSegments = packageName.split("\\.");
- if (!qualifiedNameContainsPackageName(qualifiedNameSegments, packageNameSegments)) {
- // add package to the new FQN
- for (String packageSegment : packageNameSegments) newQualifiedNameSegments.add(packageSegment);
+ public QualifiedName getFullyQualifiedName(final EObject obj) {
+ Pair<EObject, String> key = pair(obj, "fqn");
+ return cache.get(key, obj.eResource(), new Provider<QualifiedName>() {
+ public QualifiedName get() {
+ EObject current = obj;
+ String name = resolver.apply(current);
+ if (isEmpty(name)) return null;
+ QualifiedName qualifiedName = converter.toQualifiedName(name);
+ while (current.eContainer() != null) {
+ current = current.eContainer();
+ QualifiedName parentsQualifiedName = getFullyQualifiedName(current);
+ if (parentsQualifiedName != null)
+ return parentsQualifiedName.append(qualifiedName);
+ }
+ return addPackage(obj, qualifiedName);
}
- }
- newQualifiedNameSegments.addAll(qualifiedNameSegments);
- return QualifiedName.create(newQualifiedNameSegments.toArray(new String[newQualifiedNameSegments.size()]));
+ });
}
- private boolean qualifiedNameContainsPackageName(List<String> qualifiedNameSegments, String[] packageNameSegments) {
- int packageNameSegmentCount = packageNameSegments.length;
- if (qualifiedNameSegments.size() <= packageNameSegmentCount) return false;
- for (int i = 0; i < packageNameSegmentCount; i++)
- if (!qualifiedNameSegments.get(i).equals(packageNameSegments[i])) return false;
- return true;
+ private QualifiedName addPackage(EObject obj, QualifiedName qualifiedName) {
+ if (qualifiedName == null || obj instanceof Package)
+ return qualifiedName;
+ Package p = finder.packageOf(obj);
+ if (p == null) return qualifiedName;
+ String packageName = p.getName();
+ if (isEmpty(packageName)) return qualifiedName;
+ QualifiedName packageQualifiedName = converter.toQualifiedName(packageName);
+ if (qualifiedName.startsWith(packageQualifiedName)) return qualifiedName;
+ return packageQualifiedName.append(qualifiedName);
}
}
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 d46c576..3281bed 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
@@ -8,17 +8,33 @@
*/
package com.google.eclipse.protobuf.scoping;
+import static org.eclipse.emf.common.util.URI.createFileURI;
+import static org.eclipse.xtext.EcoreUtil2.getAllContentsOfType;
import static org.eclipse.xtext.resource.EObjectDescription.create;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
-import org.eclipse.emf.ecore.*;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.xtext.naming.IQualifiedNameProvider;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.scoping.IScope;
-import org.eclipse.xtext.scoping.impl.*;
+import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider;
+import org.eclipse.xtext.scoping.impl.ImportUriResolver;
+import org.eclipse.xtext.scoping.impl.SimpleScope;
-import com.google.eclipse.protobuf.protobuf.*;
import com.google.eclipse.protobuf.protobuf.Enum;
+import com.google.eclipse.protobuf.protobuf.Import;
+import com.google.eclipse.protobuf.protobuf.Literal;
+import com.google.eclipse.protobuf.protobuf.LiteralRef;
+import com.google.eclipse.protobuf.protobuf.Option;
+import com.google.eclipse.protobuf.protobuf.Property;
+import com.google.eclipse.protobuf.protobuf.Protobuf;
+import com.google.eclipse.protobuf.protobuf.Type;
+import com.google.eclipse.protobuf.protobuf.TypeReference;
import com.google.eclipse.protobuf.util.EObjectFinder;
import com.google.inject.Inject;
@@ -35,12 +51,35 @@
@Inject private EObjectFinder finder;
@Inject private Globals globals;
+ @Inject private IQualifiedNameProvider nameProvider;
+ @Inject private ImportUriResolver uriResolver;
+
+ @SuppressWarnings("unused")
+ IScope scope_TypeReference_type(TypeReference typeRef, EReference reference) {
+ Protobuf root = finder.rootOf(typeRef);
+ resolveImports(root);
+ List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
+ for (Type type : getAllContentsOfType(root, Type.class)) {
+ descriptions.add(create(nameProvider.getFullyQualifiedName(type), type));
+ descriptions.add(create(type.getName(), type));
+ }
+ return createScope(descriptions);
+ }
+ private void resolveImports(Protobuf root) {
+ EList<Import> imports = root.getImports();
+ ResourceSet resourceSet = root.eResource().getResourceSet();
+ for (Import imp : imports) {
+ String importURI = uriResolver.apply(imp);
+ resourceSet.getResource(createFileURI(importURI), true);
+ }
+ }
+
@SuppressWarnings("unused")
IScope scope_LiteralRef_literal(LiteralRef literalRef, EReference reference) {
EObject container = literalRef.eContainer();
if (container instanceof Property) {
- Enum enumType = finder.enumTypeOfProperty((Property) container);
+ Enum enumType = finder.enumTypeOf((Property) container);
if (enumType != null) return scopeForLiteralsIn(enumType);
}
if (container instanceof Option && globals.isOptimizeForOption((Option) container)) {
@@ -51,14 +90,18 @@
}
private static IScope scopeForLiteralsIn(Enum enumType) {
- List<IEObjectDescription> descriptions = descriptionsFrom(enumType);
- return new SimpleScope(descriptions, DO_NOT_IGNORE_CASE);
+ List<IEObjectDescription> descriptions = literalDescriptions(enumType);
+ return createScope(descriptions);
}
- private static List<IEObjectDescription> descriptionsFrom(Enum enumType) {
+ private static List<IEObjectDescription> literalDescriptions(Enum enumType) {
List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
for (Literal literal : enumType.getLiterals())
descriptions.add(create(literal.getName(), literal));
return descriptions;
}
+
+ private static IScope createScope(List<IEObjectDescription> descriptions) {
+ return new SimpleScope(descriptions, DO_NOT_IGNORE_CASE);
+ }
}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/EObjectFinder.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/EObjectFinder.java
index 82c470a..b5375c2 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/EObjectFinder.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/EObjectFinder.java
@@ -21,7 +21,7 @@
@Singleton
public class EObjectFinder {
- public Enum enumTypeOfProperty(Property p) {
+ public Enum enumTypeOf(Property p) {
AbstractTypeReference aTypeRef = (p).getType();
if (aTypeRef instanceof TypeReference) {
Type type = ((TypeReference) aTypeRef).getType();
@@ -30,19 +30,20 @@
return null;
}
- public ScalarType scalarTypeOfProperty(Property p) {
+ public ScalarType scalarTypeOf(Property p) {
AbstractTypeReference aTypeRef = (p).getType();
if (aTypeRef instanceof ScalarTypeReference)
return ((ScalarTypeReference) aTypeRef).getScalar();
return null;
}
- public Package findPackage(EObject o) {
+ public Package packageOf(EObject o) {
+ return rootOf(o).getPackage();
+ }
+
+ public Protobuf rootOf(EObject o) {
EObject current = o;
- while (current != null) {
- if (current instanceof Protobuf) return ((Protobuf) current).getPackage();
- current = current.eContainer();
- }
- return null;
+ while (!(current instanceof Protobuf)) current = current.eContainer();
+ return (Protobuf) current;
}
}