Merge branch 'master' of https://code.google.com/p/protobuf-dt/ into option-ref Conflicts: com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtoDescriptor.java
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 853b1c0..3e88b60 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
@@ -261,11 +261,6 @@ proposeAndAccept(name, context, acceptor); } - private ICompletionProposal createCompletionProposal(String proposal, String displayString, - ContentAssistContext context) { - return createCompletionProposal(proposal, displayString, defaultImage(), context); - } - private void proposeAndAccept(String proposalText, ContentAssistContext context, ICompletionProposalAcceptor acceptor) { acceptor.accept(createCompletionProposal(proposalText, context)); } @@ -337,7 +332,8 @@ } else if (properties.isBool(option)) { proposalText = proposalText + TRUE; } - ICompletionProposal proposal = createCompletionProposal(proposalText, displayString, context); + Image image = imageHelper.getImage(images.imageFor(Option.class)); + ICompletionProposal proposal = createCompletionProposal(proposalText, displayString, image, context); if (isStringOption && proposal instanceof ConfigurableCompletionProposal) { // set cursor between the proposal's quotes ConfigurableCompletionProposal configurable = (ConfigurableCompletionProposal) proposal; @@ -417,4 +413,9 @@ String previousWord = styledText.getTextRange(start, valueLength); return word.equals(previousWord); } + + /** {@inheritDoc} */ + @Override public void completePropertyRef_Property(EObject model, Assignment assignment, + ContentAssistContext context, ICompletionProposalAcceptor acceptor) { + } }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/OptionDescriptions.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/OptionDescriptions.java index 716232e..d92fbfb 100644 --- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/OptionDescriptions.java +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/OptionDescriptions.java
@@ -8,19 +8,23 @@ */ package com.google.eclipse.protobuf.scoping; -import static com.google.eclipse.protobuf.scoping.OptionType.*; import static java.util.Collections.emptyList; +import static org.eclipse.emf.common.util.URI.createURI; +import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents; import static org.eclipse.xtext.resource.EObjectDescription.create; import java.util.*; -import java.util.Map.Entry; +import org.eclipse.emf.common.util.*; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.*; import org.eclipse.xtext.naming.QualifiedName; import org.eclipse.xtext.resource.IEObjectDescription; +import org.eclipse.xtext.scoping.impl.ImportUriResolver; 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.*; import com.google.inject.Inject; /** @@ -28,19 +32,14 @@ */ class OptionDescriptions { - private static final Map<Class<?>, OptionType> OPTION_TYPES_BY_CONTAINER = new HashMap<Class<?>, OptionType>(); - - static { - OPTION_TYPES_BY_CONTAINER.put(Protobuf.class, FILE); - OPTION_TYPES_BY_CONTAINER.put(Enum.class, ENUM); - OPTION_TYPES_BY_CONTAINER.put(Message.class, MESSAGE); - OPTION_TYPES_BY_CONTAINER.put(Service.class, SERVICE); - OPTION_TYPES_BY_CONTAINER.put(Rpc.class, RPC); - } - @Inject private ProtoDescriptorProvider descriptorProvider; + @Inject private ProtobufElementFinder finder; + @Inject private ImportedNamesProvider importedNamesProvider; + @Inject private Imports imports; @Inject private LocalNamesProvider localNamesProvider; + @Inject private PackageResolver packageResolver; @Inject private QualifiedNameDescriptions qualifiedNamesDescriptions; + @Inject private ImportUriResolver uriResolver; Collection <IEObjectDescription> builtInOptionProperties(BuiltInOption option) { ProtoDescriptor descriptor = descriptorProvider.get(); @@ -49,12 +48,11 @@ return emptyList(); } - Collection <IEObjectDescription> localCustomOptionProperties(EObject root, CustomOption option) { - return localCustomOptionProperties(root, option, 0); + Collection <IEObjectDescription> localCustomOptionProperties(EObject root, OptionType optionType) { + return localCustomOptionProperties(root, optionType, 0); } - private Collection <IEObjectDescription> localCustomOptionProperties(EObject root, CustomOption option, int level) { - OptionType optionType = optionType(option); + private Collection <IEObjectDescription> localCustomOptionProperties(EObject root, OptionType optionType, int level) { if (optionType == null) return emptyList(); List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>(); for (EObject element : root.eContents()) { @@ -72,23 +70,87 @@ continue; } if (element instanceof Message) { - descriptions.addAll(localCustomOptionProperties(element, option, level + 1)); + descriptions.addAll(localCustomOptionProperties(element, optionType, level + 1)); } } return descriptions; } - private OptionType optionType(CustomOption option) { - EObject container = option.eContainer(); - for (Entry<Class<?>, OptionType> optionTypeByContainer : OPTION_TYPES_BY_CONTAINER.entrySet()) { - if (optionTypeByContainer.getKey().isInstance(container)) { - return optionTypeByContainer.getValue(); - } - } - return null; + Collection<IEObjectDescription> importedCustomOptionProperties(Protobuf root, OptionType optionType) { + List<Import> allImports = finder.importsIn(root); + if (allImports.isEmpty()) return emptyList(); + ResourceSet resourceSet = root.eResource().getResourceSet(); + return importedCustomOptionProperties(allImports, finder.packageOf(root), resourceSet, optionType); } - private boolean isExtendingOptionMessage(EObject o, OptionType optionType) { + private Collection<IEObjectDescription> importedCustomOptionProperties(List<Import> allImports, Package aPackage, + ResourceSet resourceSet, OptionType optionType) { + List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>(); + for (Import anImport : allImports) { + if (imports.isImportingDescriptor(anImport)) continue; + Resource importedResource = importedResource(anImport, resourceSet); + Protobuf importedRoot = finder.rootOf(importedResource); + if (importedRoot != null) { + descriptions.addAll(publicImportedCustomOptionProperties(importedRoot, optionType)); + if (arePackagesRelated(aPackage, importedRoot)) { + descriptions.addAll(localCustomOptionProperties(importedRoot, optionType)); + continue; + } + } + descriptions.addAll(localCustomOptionProperties(importedResource, optionType)); + } + return descriptions; + } + + private Resource importedResource(Import anImport, ResourceSet resourceSet) { + URI importUri = createURI(uriResolver.apply(anImport)); + try { + return resourceSet.getResource(importUri, true); + } catch (Throwable t) { + return null; + } + } + + private <T extends Type> Collection<IEObjectDescription> publicImportedCustomOptionProperties(Protobuf root, + OptionType optionType) { + List<Import> allImports = finder.publicImportsIn(root); + if (allImports.isEmpty()) return emptyList(); + ResourceSet resourceSet = root.eResource().getResourceSet(); + return importedCustomOptionProperties(allImports, finder.packageOf(root), resourceSet, optionType); + } + + private boolean arePackagesRelated(Package aPackage, EObject root) { + Package p = finder.packageOf(root); + return packageResolver.areRelated(aPackage, p); + } + + private Collection<IEObjectDescription> describe(Collection<Property> properties) { + List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>(); + for (Property p : properties) { + descriptions.add(create(p.getName(), p)); + } + return descriptions; + } + + private Collection<IEObjectDescription> localCustomOptionProperties(Resource resource, OptionType optionType) { + List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>(); + TreeIterator<Object> contents = getAllContents(resource, true); + while (contents.hasNext()) { + Object next = contents.next(); + if (!isExtendingOptionMessage(next, optionType)) continue; + ExtendMessage extend = (ExtendMessage) next; + for (MessageElement e : extend.getElements()) { + if (!(e instanceof Property)) continue; + descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(e)); + for (QualifiedName name : importedNamesProvider.namesOf(e)) { + descriptions.add(create(name, e)); + } + } + } + return descriptions; + } + + private boolean isExtendingOptionMessage(Object o, OptionType optionType) { if (!(o instanceof ExtendMessage)) return false; Message message = messageFrom((ExtendMessage) o); if (message == null) return false; @@ -99,12 +161,4 @@ MessageRef ref = extend.getMessage(); return ref == null ? null : ref.getType(); } - - private Collection<IEObjectDescription> describe(Collection<Property> properties) { - List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>(); - for (Property p : properties) { - descriptions.add(create(p.getName(), p)); - } - return descriptions; - } }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/OptionType.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/OptionType.java index f5893a3..2c75f54 100644 --- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/OptionType.java +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/OptionType.java
@@ -8,6 +8,14 @@ */ package com.google.eclipse.protobuf.scoping; +import java.util.*; +import java.util.Map.Entry; + +import org.eclipse.emf.ecore.EObject; + +import com.google.eclipse.protobuf.protobuf.*; +import com.google.eclipse.protobuf.protobuf.Enum; + /** * @author alruiz@google.com (Alex Ruiz) */ @@ -15,9 +23,29 @@ FILE("FileOptions"), MESSAGE("MessageOptions"), FIELD("FieldOptions"), ENUM("EnumOptions"), LITERAL("EnumValueOptions"), SERVICE("ServiceOptions"), RPC("MethodOptions"); + private static final Map<Class<?>, OptionType> OPTION_TYPES_BY_CONTAINER = new HashMap<Class<?>, OptionType>(); + + static { + OPTION_TYPES_BY_CONTAINER.put(Protobuf.class, FILE); + OPTION_TYPES_BY_CONTAINER.put(Enum.class, ENUM); + OPTION_TYPES_BY_CONTAINER.put(Message.class, MESSAGE); + OPTION_TYPES_BY_CONTAINER.put(Service.class, SERVICE); + OPTION_TYPES_BY_CONTAINER.put(Rpc.class, RPC); + } + final String messageName; private OptionType(String messageName) { this.messageName = messageName; } -} \ No newline at end of file + + static OptionType optionType(CustomOption option) { + EObject container = option.eContainer(); + for (Entry<Class<?>, OptionType> optionTypeByContainer : OPTION_TYPES_BY_CONTAINER.entrySet()) { + if (optionTypeByContainer.getKey().isInstance(container)) { + return optionTypeByContainer.getValue(); + } + } + return null; + } +}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtoDescriptor.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtoDescriptor.java index 70bdd4c..af6225f 100644 --- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtoDescriptor.java +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtoDescriptor.java
@@ -46,11 +46,11 @@ private static final Map<String, OptionType> OPTION_DEFINITION_BY_NAME = new HashMap<String, OptionType>(); static { - addOptionTypeMappings(); + addOptionTypes(FILE, MESSAGE, FIELD, ENUM); } - private static void addOptionTypeMappings() { - for (OptionType type : OptionType.values()) { + private static void addOptionTypes(OptionType...types) { + for (OptionType type : types) { OPTION_DEFINITION_BY_NAME.put(type.messageName, type); } } @@ -133,23 +133,33 @@ } /** - * Returns the options available for the given option container. The returned options are defined in + * Returns the options available for the given option or option container. The returned options are defined in * {@code google/protobuf/descriptor.proto} (more details can be found * <a href=http://code.google.com/apis/protocolbuffers/docs/proto.html#options" target="_blank">here</a>.) - * @param optionContainer the given container of an option. - * @return the options available for the given option container, or an empty collection if the are not any - * options available for the given option container. + * @param o the given option or option container. + * @return the options available for the given option or option container, or an empty collection if the are not any + * options available. */ - public Collection<Property> availableOptionPropertiesFor(EObject optionContainer) { - if (optionContainer instanceof Protobuf) return optionsOfType(FILE); - if (optionContainer instanceof Enum) return optionsOfType(ENUM); - if (optionContainer instanceof Message) return optionsOfType(MESSAGE); - if (optionContainer instanceof Service) return optionsOfType(SERVICE); - if (optionContainer instanceof Rpc) return optionsOfType(RPC); + public Collection<Property> availableOptionPropertiesFor(EObject o) { + EObject target = o; + if (target instanceof BuiltInOption) target = target.eContainer(); + if (target instanceof Protobuf) return fileOptions(); + if (target instanceof Enum) return enumOptions(); + if (target instanceof Message) return messageOptions(); return emptyList(); } /** + * Returns all the file-level options available. These are the options defined in + * {@code google/protobuf/descriptor.proto} (more details can be found + * <a href=http://code.google.com/apis/protocolbuffers/docs/proto.html#options" target="_blank">here</a>.) + * @return all the file-level options available. + */ + public Collection<Property> fileOptions() { + return optionsOfType(FILE); + } + + /** * Looks up an option per name, as defined in {@code google/protobuf/descriptor.proto} * (more details can be found <a * href=http://code.google.com/apis/protocolbuffers/docs/proto.html#options" target="_blank">here</a>.) @@ -184,6 +194,16 @@ } /** + * Returns all the message-level options available. These are the options defined in + * {@code google/protobuf/descriptor.proto} (more details can be found + * <a href=http://code.google.com/apis/protocolbuffers/docs/proto.html#options" target="_blank">here</a>.) + * @return all the message-level options available. + */ + public Collection<Property> messageOptions() { + return optionsOfType(MESSAGE); + } + + /** * Returns all the field-level options available. These are the options defined in * {@code google/protobuf/descriptor.proto} (more details can be found * <a href=http://code.google.com/apis/protocolbuffers/docs/proto.html#options" target="_blank">here</a>.) @@ -192,7 +212,17 @@ public Collection<Property> fieldOptions() { return optionsOfType(FIELD); } - + + /** + * Returns all the enum-level options available. These are the options defined in + * {@code google/protobuf/descriptor.proto} (more details can be found + * <a href=http://code.google.com/apis/protocolbuffers/docs/proto.html#options" target="_blank">here</a>.) + * @return all the enum-level options available. + */ + public Collection<Property> enumOptions() { + return optionsOfType(ENUM); + } + private Collection<Property> optionsOfType(OptionType type) { return unmodifiableCollection(optionsByType.get(type).values()); }
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 be4bcc9..041fcc1 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,6 +8,8 @@ */ package com.google.eclipse.protobuf.scoping; +import static com.google.eclipse.protobuf.scoping.OptionType.optionType; + import java.util.*; import org.eclipse.emf.ecore.*; @@ -97,7 +99,13 @@ } if (mayBeOption instanceof CustomOption) { Protobuf root = finder.rootOf(propertyRef); - descriptions.addAll(optionDescriptions.localCustomOptionProperties(root, (CustomOption) mayBeOption)); + OptionType optionType = optionType((CustomOption) mayBeOption); + EObject current = mayBeOption.eContainer(); + while (current != null) { + descriptions.addAll(optionDescriptions.localCustomOptionProperties(current, optionType)); + current = current.eContainer(); + } + descriptions.addAll(optionDescriptions.importedCustomOptionProperties(root, optionType)); } return createScope(descriptions); }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/QualifiedNames.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/QualifiedNames.java index eb5bdc0..a073fe8 100644 --- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/QualifiedNames.java +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/QualifiedNames.java
@@ -33,7 +33,7 @@ return QualifiedName.create(segments.toArray(new String[segments.size()])); } - List<QualifiedName> addPackageNameSegments(QualifiedName name, Package p) { + Collection<QualifiedName> addPackageNameSegments(QualifiedName name, Package p) { QualifiedName current = name; List<String> segments = fqnSegments(p); int segmentCount = segments.size();
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeDescriptions.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeDescriptions.java index 5082138..8892b06 100644 --- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeDescriptions.java +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeDescriptions.java
@@ -19,12 +19,12 @@ import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.*; import org.eclipse.xtext.naming.QualifiedName; -import org.eclipse.xtext.resource.*; +import org.eclipse.xtext.resource.IEObjectDescription; import org.eclipse.xtext.scoping.impl.ImportUriResolver; import com.google.eclipse.protobuf.protobuf.*; import com.google.eclipse.protobuf.protobuf.Package; -import com.google.eclipse.protobuf.util.ProtobufElementFinder; +import com.google.eclipse.protobuf.util.*; import com.google.inject.Inject; /** @@ -35,6 +35,7 @@ @Inject private ProtoDescriptorProvider descriptorProvider; @Inject private ProtobufElementFinder finder; @Inject private ImportedNamesProvider importedNamesProvider; + @Inject private Imports imports; @Inject private LocalNamesProvider localNamesProvider; @Inject private PackageResolver packageResolver; @Inject private QualifiedNameDescriptions qualifiedNamesDescriptions; @@ -65,19 +66,20 @@ <T extends Type> Collection<IEObjectDescription> importedTypes(Protobuf root, Class<T> targetType) { List<Import> allImports = finder.importsIn(root); if (allImports.isEmpty()) return emptyList(); - return importedTypes(allImports, finder.packageOf(root), targetType); + ResourceSet resourceSet = root.eResource().getResourceSet(); + return importedTypes(allImports, finder.packageOf(root), resourceSet, targetType); } private <T extends Type> Collection<IEObjectDescription> importedTypes(List<Import> allImports, Package aPackage, - Class<T> targetType) { + ResourceSet resourceSet, Class<T> targetType) { List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>(); for (Import anImport : allImports) { - if (isImportingDescriptor(anImport)) { + if (imports.isImportingDescriptor(anImport)) { descriptions.addAll(allBuiltInTypes(targetType)); continue; } - Resource importedResource = importedResourceFrom(anImport); - Protobuf importedRoot = rootElementOf(importedResource); + Resource importedResource = importedResource(anImport, resourceSet); + Protobuf importedRoot = finder.rootOf(importedResource); if (importedRoot != null) { descriptions.addAll(publicImportedTypes(importedRoot, targetType)); if (arePackagesRelated(aPackage, importedRoot)) { @@ -85,16 +87,11 @@ continue; } } - descriptions.addAll(children(importedResource, targetType)); + descriptions.addAll(localTypes(importedResource, targetType)); } return descriptions; } - private boolean isImportingDescriptor(Import anImport) { - String descriptorLocation = descriptorProvider.descriptorLocation().toString(); - return descriptorLocation.equals(anImport.getImportURI()); - } - private <T extends Type> Collection<IEObjectDescription> allBuiltInTypes(Class<T> targetType) { List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>(); ProtoDescriptor descriptor = descriptorProvider.get(); @@ -106,14 +103,7 @@ return descriptions; } - private <T extends Type> Collection<IEObjectDescription> publicImportedTypes(Protobuf root, Class<T> targetType) { - List<Import> allImports = finder.publicImportsIn(root); - if (allImports.isEmpty()) return emptyList(); - return importedTypes(allImports, finder.packageOf(root), targetType); - } - - private Resource importedResourceFrom(Import anImport) { - ResourceSet resourceSet = finder.rootOf(anImport).eResource().getResourceSet(); + private Resource importedResource(Import anImport, ResourceSet resourceSet) { URI importUri = createURI(uriResolver.apply(anImport)); try { return resourceSet.getResource(importUri, true); @@ -122,17 +112,11 @@ } } - private Protobuf rootElementOf(Resource resource) { - if (resource instanceof XtextResource) { - EObject root = ((XtextResource) resource).getParseResult().getRootASTElement(); - return (Protobuf) root; - } - TreeIterator<Object> contents = getAllContents(resource, true); - if (contents.hasNext()) { - Object next = contents.next(); - if (next instanceof Protobuf) return (Protobuf) next; - } - return null; + private <T extends Type> Collection<IEObjectDescription> publicImportedTypes(Protobuf root, Class<T> targetType) { + List<Import> allImports = finder.publicImportsIn(root); + if (allImports.isEmpty()) return emptyList(); + ResourceSet resourceSet = root.eResource().getResourceSet(); + return importedTypes(allImports, finder.packageOf(root), resourceSet, targetType); } private boolean arePackagesRelated(Package aPackage, EObject root) { @@ -140,7 +124,7 @@ return packageResolver.areRelated(aPackage, p); } - private <T extends Type> Collection<IEObjectDescription> children(Resource resource, Class<T> targetType) { + private <T extends Type> Collection<IEObjectDescription> localTypes(Resource resource, Class<T> targetType) { List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>(); TreeIterator<Object> contents = getAllContents(resource, true); while (contents.hasNext()) {
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/Imports.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/Imports.java index ea34fd0..d2ed78e 100644 --- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/Imports.java +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/Imports.java
@@ -11,7 +11,8 @@ import static com.google.eclipse.protobuf.scoping.ProtoDescriptor.DESCRIPTOR_IMPORT_URI; import com.google.eclipse.protobuf.protobuf.Import; -import com.google.inject.Singleton; +import com.google.eclipse.protobuf.scoping.ProtoDescriptorProvider; +import com.google.inject.*; /** * Utility methods related to imports. @@ -21,6 +22,8 @@ @Singleton public class Imports { + @Inject private ProtoDescriptorProvider descriptorProvider; + /** * Indicates whether the URI of the given import is equal to the path of descriptor.proto * ("google/protobuf/descriptor.proto"). @@ -42,4 +45,14 @@ public boolean isUnresolvedDescriptorUri(String uri) { return DESCRIPTOR_IMPORT_URI.equals(uri); } + + /** + * Indicates whether the given <code>{@link Import}</code> is pointing to descriptor.proto. + * @param anImport the given import to check. + * @return {@code true} if the given import is pointing to descriptor.proto, {@code false} otherwise. + */ + public boolean isImportingDescriptor(Import anImport) { + String descriptorLocation = descriptorProvider.descriptorLocation().toString(); + return descriptorLocation.equals(anImport.getImportURI()); + } }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/ProtobufElementFinder.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/ProtobufElementFinder.java index 64ba56d..e3a255c 100644 --- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/ProtobufElementFinder.java +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/ProtobufElementFinder.java
@@ -9,10 +9,14 @@ package com.google.eclipse.protobuf.util; import static java.util.Collections.unmodifiableList; +import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents; import java.util.*; +import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.xtext.resource.XtextResource; import com.google.eclipse.protobuf.protobuf.*; import com.google.eclipse.protobuf.protobuf.Enum; @@ -103,4 +107,21 @@ } return unmodifiableList(imports); } -} + + /** + * Returns the root element of the given resource. + * @param resource the given resource. + * @return the root element of the given resource, or {@code null} if the given resource does not have a root element. + */ + public Protobuf rootOf(Resource resource) { + if (resource instanceof XtextResource) { + EObject root = ((XtextResource) resource).getParseResult().getRootASTElement(); + return (Protobuf) root; + } + TreeIterator<Object> contents = getAllContents(resource, true); + if (contents.hasNext()) { + Object next = contents.next(); + if (next instanceof Protobuf) return (Protobuf) next; + } + return null; + }}