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