In progress: [Issue 155] Editor does not support complex custom options.
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_SimplePropertyRef_property_Test.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_MessagePropertyRef_messageProperty_Test.java
similarity index 79%
rename from com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_SimplePropertyRef_property_Test.java
rename to com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_MessagePropertyRef_messageProperty_Test.java
index 13bbbc5..0eb89a7 100644
--- a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_SimplePropertyRef_property_Test.java
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_MessagePropertyRef_messageProperty_Test.java
@@ -23,11 +23,11 @@
import org.junit.*;
/**
- * Tests for <code>{@link ProtobufScopeProvider#scope_SimplePropertyRef_property(SimplePropertyRef, EReference)}</code>
+ * Tests for <code>{@link ProtobufScopeProvider#scope_MessagePropertyRef_messageProperty(MessagePropertyRef, EReference)}</code>.
*
* @author alruiz@google.com (Alex Ruiz)
*/
-public class ProtobufScopeProvider_scope_SimplePropertyRef_property_Test {
+public class ProtobufScopeProvider_scope_MessagePropertyRef_messageProperty_Test {
private static EReference reference;
@@ -46,7 +46,7 @@
// import 'google/protobuf/descriptor.proto';
//
// message Type {
- // optional int32 code = 1;
+ // optional double code = 1;
// optional string name = 2;
// }
//
@@ -57,7 +57,8 @@
// option (type).code = 68;
@Test public void should_provide_Property_fields_for_custom_option_field() {
CustomOption option = xtext.find("type", ")", CustomOption.class);
- IScope scope = provider.scope_SimplePropertyRef_property(option.getPropertyField(), reference);
+ MessagePropertyRef optionField = (MessagePropertyRef) option.getOptionFields().get(0);
+ IScope scope = provider.scope_MessagePropertyRef_messageProperty(optionField, reference);
Message typeMessage = xtext.find("Type", " {", Message.class);
assertThat(descriptionsIn(scope), containAllPropertiesIn(typeMessage));
}
@@ -65,7 +66,7 @@
// import 'google/protobuf/descriptor.proto';
//
// message Type {
- // optional int32 code = 1;
+ // optional double code = 1;
// optional string name = 2;
// }
//
@@ -78,7 +79,8 @@
// }
@Test public void should_provide_Property_fields_for_custom_field_option_field() {
CustomFieldOption option = xtext.find("type", ")", CustomFieldOption.class);
- IScope scope = provider.scope_SimplePropertyRef_property(option.getPropertyField(), reference);
+ MessagePropertyRef optionField = (MessagePropertyRef) option.getOptionFields().get(0);
+ IScope scope = provider.scope_MessagePropertyRef_messageProperty(optionField, reference);
Message typeMessage = xtext.find("Type", " {", Message.class);
assertThat(descriptionsIn(scope), containAllPropertiesIn(typeMessage));
}
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/model/util/ModelFinder_extensionsFrom_Test.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/model/util/ModelFinder_extensionsFrom_Test.java
new file mode 100644
index 0000000..a853ce7
--- /dev/null
+++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/model/util/ModelFinder_extensionsFrom_Test.java
@@ -0,0 +1,48 @@
+/*
+ * 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.model.util;
+
+import static com.google.eclipse.protobuf.junit.core.Setups.unitTestSetup;
+import static com.google.eclipse.protobuf.junit.core.XtextRule.createWith;
+import static org.junit.Assert.assertSame;
+
+import com.google.eclipse.protobuf.junit.core.XtextRule;
+import com.google.eclipse.protobuf.protobuf.*;
+
+import org.junit.*;
+
+import java.util.*;
+
+/**
+ * Tests for <code>{@link ModelFinder#extensionsOf(Message)}</code>.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class ModelFinder_extensionsFrom_Test {
+
+ @Rule public XtextRule xtext = createWith(unitTestSetup());
+
+ private ModelFinder finder;
+
+ @Before public void setUp() {
+ finder = xtext.getInstanceOf(ModelFinder.class);
+ }
+
+ // message Person {
+ // optional string name = 1;
+ // }
+ //
+ // extend Person {}
+ @Test public void should_return_extensions_of_message() {
+ Message m = xtext.find("Person", " {", Message.class);
+ List<ExtendMessage> extensions = new ArrayList<ExtendMessage>(finder.extensionsOf(m));
+ Message referred = extensions.get(0).getMessage().getType();
+ assertSame(m, referred);
+ }
+}
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/model/util/ModelFinder_messageFrom_Test.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/model/util/ModelFinder_messageFrom_Test.java
new file mode 100644
index 0000000..88abdd9
--- /dev/null
+++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/model/util/ModelFinder_messageFrom_Test.java
@@ -0,0 +1,53 @@
+/*
+ * 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.model.util;
+
+import static com.google.eclipse.protobuf.junit.core.Setups.unitTestSetup;
+import static com.google.eclipse.protobuf.junit.core.XtextRule.createWith;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import com.google.eclipse.protobuf.junit.core.XtextRule;
+import com.google.eclipse.protobuf.protobuf.*;
+
+import org.junit.*;
+
+/**
+ * Tests for <code>{@link ModelFinder#messageFrom(ExtendMessage)}</code>.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class ModelFinder_messageFrom_Test {
+
+ @Rule public XtextRule xtext = createWith(unitTestSetup());
+
+ private ModelFinder finder;
+
+ @Before public void setUp() {
+ finder = xtext.getInstanceOf(ModelFinder.class);
+ }
+
+ // message Person {
+ // optional string name = 1;
+ // }
+ //
+ // extend Person {}
+ @Test public void should_return_message_from_extension() {
+ ExtendMessage extension = xtext.find("Person", " {}", ExtendMessage.class);
+ Message message = finder.messageFrom(extension);
+ assertThat(message.getName(), equalTo("Person"));
+ }
+
+ @Test public void should_return_null_if_extension_is_not_referring_to_message() {
+ ExtendMessage extension = mock(ExtendMessage.class);
+ when(extension.getMessage()).thenReturn(null);
+ assertNull(finder.messageFrom(extension));
+ }
+}
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 ef89dcf..f15b361 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
@@ -405,7 +405,7 @@
ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
}
- @Override public void completeSimplePropertyRef_Property(EObject model, Assignment assignment,
+ @Override public void completeMessagePropertyRef_MessageProperty(EObject model, Assignment assignment,
ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
}
@@ -444,20 +444,35 @@
acceptor.accept(proposal);
}
- @Override public void completeCustomOption_PropertyField(EObject model, Assignment assignment,
+ @Override public void completeCustomOption_OptionFields(EObject model, Assignment assignment,
ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
- if (!(model instanceof CustomOption)) return;
- Property property = options.propertyFrom((CustomOption) model);
- proposeAndAcceptOptionFields(property, context, acceptor);
+ super.completeCustomOption_OptionFields(model, assignment, context, acceptor);
+ }
+
+ @Override public void completeCustomFieldOption_OptionFields(EObject model, Assignment assignment,
+ ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
+ super.completeCustomFieldOption_OptionFields(model, assignment, context, acceptor);
}
- @Override public void completeCustomFieldOption_PropertyField(EObject model, Assignment assignment,
- ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
- if (!(model instanceof CustomFieldOption)) return;
- Property property = fieldOptions.propertyFrom((CustomFieldOption) model);
- proposeAndAcceptOptionFields(property, context, acceptor);
+ @Override public void complete_MessagePropertyRef(EObject model, RuleCall ruleCall, ContentAssistContext context,
+ ICompletionProposalAcceptor acceptor) {
+ super.complete_MessagePropertyRef(model, ruleCall, context, acceptor);
}
+// @Override public void completeCustomOption_PropertyField(EObject model, Assignment assignment,
+// ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
+// if (!(model instanceof CustomOption)) return;
+// Property property = options.propertyFrom((CustomOption) model);
+// proposeAndAcceptOptionFields(property, context, acceptor);
+// }
+//
+// @Override public void completeCustomFieldOption_PropertyField(EObject model, Assignment assignment,
+// ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
+// if (!(model instanceof CustomFieldOption)) return;
+// Property property = fieldOptions.propertyFrom((CustomFieldOption) model);
+// proposeAndAcceptOptionFields(property, context, acceptor);
+// }
+
private void proposeAndAcceptOptionFields(Property property, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
Message message = finder.messageTypeOf(property);
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/Protobuf.xtext b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/Protobuf.xtext
index e90bb84..1698f3f 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/Protobuf.xtext
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/Protobuf.xtext
@@ -200,8 +200,9 @@
'option' property=PropertyRef '=' value=ValueRef ';';
CustomOption:
- 'option' '(' property=PropertyRef ')'('.' propertyField = SimplePropertyRef)? '=' value=ValueRef ';';
-
+ 'option' '(' property=PropertyRef ')'
+ ('.' optionFields+=OptionField ('.' optionFields+=OptionField)*)? '=' value=ValueRef ';';
+
FieldOption:
DefaultValueFieldOption | NativeFieldOption | CustomFieldOption;
@@ -212,10 +213,18 @@
property=PropertyRef '=' value=ValueRef;
CustomFieldOption:
- '(' property=PropertyRef ')'('.' propertyField = SimplePropertyRef)? '=' value=ValueRef;
+ '(' property=PropertyRef ')'
+ ('.' optionFields+=OptionField ('.' optionFields+=OptionField)*)? '=' value=ValueRef;
PropertyRef:
property=[Property|QualifiedName];
-SimplePropertyRef:
- property=[Property];
\ No newline at end of file
+OptionField:
+ MessagePropertyRef | ExtendMessagePropertyRef;
+
+MessagePropertyRef:
+ messageProperty=[Property];
+
+ExtendMessagePropertyRef:
+ '(' extendMessageProperty=[Property|QualifiedName] ')';
+
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/FieldOptions.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/FieldOptions.java
index 41d1365..2b6cac0 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/FieldOptions.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/FieldOptions.java
@@ -74,7 +74,8 @@
* one cannot be found.
*/
public Property fieldFrom(CustomFieldOption option) {
- SimplePropertyRef ref = option.getPropertyField();
- return (ref == null) ? null : ref.getProperty();
+ return null;
+ // SimplePropertyRef ref = option.getPropertyField();
+ // return (ref == null) ? null : ref.getProperty();
}
}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/ModelFinder.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/ModelFinder.java
index 3529d39..9fbb8f0 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/ModelFinder.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/ModelFinder.java
@@ -10,18 +10,19 @@
import static java.util.Collections.unmodifiableList;
import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents;
+import static org.eclipse.xtext.EcoreUtil2.getAllContentsOfType;
-import java.util.*;
+import com.google.eclipse.protobuf.protobuf.*;
+import com.google.eclipse.protobuf.protobuf.Enum;
+import com.google.eclipse.protobuf.protobuf.Package;
+import com.google.inject.Singleton;
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;
-import com.google.eclipse.protobuf.protobuf.Package;
-import com.google.inject.Singleton;
+import java.util.*;
/**
* Utility methods to find elements in a parser proto file.
@@ -32,6 +33,31 @@
public class ModelFinder {
/**
+ * Returns all the <strong>local</strong> extensions of the given message.
+ * @param m the given message.
+ * @return all the <strong>local</strong> extensions of the given message, or an empty collection if none is found.
+ */
+ public Collection<ExtendMessage> extensionsOf(Message m) {
+ Set<ExtendMessage> extensions = new HashSet<ExtendMessage>();
+ Protobuf root = rootOf(m);
+ for (ExtendMessage extension : getAllContentsOfType(root, ExtendMessage.class)) {
+ Message referred = messageFrom(extension);
+ if (m.equals(referred)) extensions.add(extension);
+ }
+ return extensions;
+ }
+
+ /**
+ * Returns the message from the given extension.
+ * @param e the given extension.
+ * @return the message from the given extension, or {@code null} if the extension is not referring to a message.
+ */
+ public Message messageFrom(ExtendMessage e) {
+ MessageRef ref = e.getMessage();
+ return ref == null ? null : ref.getType();
+ }
+
+ /**
* Returns the message type of the given property, only if the type of the given property is a message.
* @param p the given property.
* @return the message type of the given property or {@code null} if the type of the given property is not message.
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Options.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Options.java
index de6cd8f..afa0b5a 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Options.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Options.java
@@ -47,7 +47,8 @@
* cannot be found.
*/
public Property fieldFrom(CustomOption option) {
- SimplePropertyRef ref = option.getPropertyField();
- return (ref == null) ? null : ref.getProperty();
+ return null;
+ // SimplePropertyRef ref = option.getPropertyField();
+ // return (ref == null) ? null : ref.getProperty();
}
}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionDescriptions.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionDescriptions.java
deleted file mode 100644
index 58a67d2..0000000
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionDescriptions.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * 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.scoping.OptionType.typeOf;
-import static java.util.Collections.emptyList;
-import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents;
-import static org.eclipse.xtext.resource.EObjectDescription.create;
-
-import java.util.*;
-
-import org.eclipse.emf.common.util.TreeIterator;
-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 com.google.eclipse.protobuf.model.util.*;
-import com.google.eclipse.protobuf.protobuf.*;
-import com.google.eclipse.protobuf.protobuf.Package;
-import com.google.inject.Inject;
-
-/**
- * @author alruiz@google.com (Alex Ruiz)
- */
-class CustomOptionDescriptions {
-
- @Inject private ModelFinder finder;
- @Inject private Imports imports;
- @Inject private LocalNamesProvider localNamesProvider;
- @Inject private Packages packages;
- @Inject private QualifiedNameDescriptions qualifiedNamesDescriptions;
- @Inject private Resources resources;
-
- public Collection <IEObjectDescription> properties(CustomOption option) {
- return allProperties(option, typeOf(option));
- }
-
- public Collection <IEObjectDescription> properties(CustomFieldOption option) {
- return allProperties(option, typeOf(option));
- }
-
- private Collection <IEObjectDescription> allProperties(EObject option, OptionType type) {
- Set<IEObjectDescription> descriptions = new LinkedHashSet<IEObjectDescription>();
- EObject current = option.eContainer();
- while (current != null) {
- descriptions.addAll(local(current, type));
- current = current.eContainer();
- }
- Protobuf root = finder.rootOf(option);
- descriptions.addAll(imported(root, type));
- return descriptions;
- }
-
- private Collection <IEObjectDescription> local(EObject root, OptionType optionType) {
- return local(root, optionType, 0);
- }
-
- private Collection <IEObjectDescription> local(EObject root, OptionType optionType, int level) {
- if (optionType == null) return emptyList();
- Set<IEObjectDescription> descriptions = new LinkedHashSet<IEObjectDescription>();
- for (EObject element : root.eContents()) {
- if (isExtendingOptionMessage(element, optionType)) {
- ExtendMessage extend = (ExtendMessage) element;
- for (MessageElement e : extend.getElements()) {
- if (!(e instanceof Property)) continue;
- Property p = (Property) e;
- List<QualifiedName> names = localNamesProvider.namesOf(p);
- int nameCount = names.size();
- for (int i = level; i < nameCount; i++) {
- descriptions.add(create(names.get(i), p));
- }
- descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(p));
- }
- }
- if (element instanceof Message) {
- descriptions.addAll(local(element, optionType, level + 1));
- }
- }
- return descriptions;
- }
-
- private Collection<IEObjectDescription> imported(Protobuf root, OptionType optionType) {
- List<Import> allImports = finder.importsIn(root);
- if (allImports.isEmpty()) return emptyList();
- ResourceSet resourceSet = root.eResource().getResourceSet();
- return imported(allImports, finder.packageOf(root), resourceSet, optionType);
- }
-
- private Collection<IEObjectDescription> imported(List<Import> allImports, Package aPackage,
- ResourceSet resourceSet, OptionType optionType) {
- Set<IEObjectDescription> descriptions = new LinkedHashSet<IEObjectDescription>();
- for (Import anImport : allImports) {
- if (imports.isImportingDescriptor(anImport)) continue;
- Resource importedResource = resources.importedResource(anImport, resourceSet);
- Protobuf importedRoot = finder.rootOf(importedResource);
- if (importedRoot != null) {
- descriptions.addAll(publicImported(importedRoot, optionType));
- if (arePackagesRelated(aPackage, importedRoot)) {
- descriptions.addAll(local(importedRoot, optionType));
- continue;
- }
- }
- descriptions.addAll(local(importedResource, optionType));
- }
- return descriptions;
- }
-
- private <T extends Type> Collection<IEObjectDescription> publicImported(Protobuf root, OptionType optionType) {
- List<Import> allImports = finder.publicImportsIn(root);
- if (allImports.isEmpty()) return emptyList();
- ResourceSet resourceSet = root.eResource().getResourceSet();
- return imported(allImports, finder.packageOf(root), resourceSet, optionType);
- }
-
- private boolean arePackagesRelated(Package aPackage, EObject root) {
- Package p = finder.packageOf(root);
- return packages.areRelated(aPackage, p);
- }
-
- private Collection<IEObjectDescription> local(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((EObject) next, optionType)) continue;
- ExtendMessage extend = (ExtendMessage) next;
- for (MessageElement e : extend.getElements()) {
- if (!(e instanceof Property)) continue;
- Property p = (Property) e;
- descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(p));
- // TODO verify that call to 'importedNamesProvider.namesOf' is not necessary
- }
- }
- return descriptions;
- }
-
- private boolean isExtendingOptionMessage(EObject o, OptionType optionType) {
- if (!(o instanceof ExtendMessage)) return false;
- Message message = messageFrom((ExtendMessage) o);
- if (message == null) return false;
- return optionType.messageName().equals(message.getName());
- }
-
- private Message messageFrom(ExtendMessage extend) {
- MessageRef ref = extend.getMessage();
- return ref == null ? null : ref.getType();
- }
-
- /*
- * Scope for 'y' in:
- * option Type (x).y = 0;
- */
- Collection <IEObjectDescription> fields(Property optionProperty) {
- Message propertyType = finder.messageTypeOf(optionProperty);
- if (propertyType == null) return emptyList();
- Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
- for (MessageElement e : propertyType.getElements()) {
- if (!(e instanceof Property)) continue;
- Property optionPropertyField = (Property) e;
- descriptions.add(create(optionPropertyField.getName(), optionPropertyField));
- }
- return descriptions;
- }
-}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionSearchDelegate.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionSearchDelegate.java
new file mode 100644
index 0000000..8f60b2a
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionSearchDelegate.java
@@ -0,0 +1,35 @@
+/*
+ * 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 org.eclipse.xtext.resource.IEObjectDescription;
+
+import java.util.Collection;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class CustomOptionSearchDelegate extends ExtendMessageSearchDelegate {
+
+ @Override public Collection<IEObjectDescription> descriptions(Object target, Object criteria) {
+ OptionType optionType = optionTypeFrom(criteria);
+ return super.descriptions(target, optionType.messageName());
+ }
+
+ @Override public Collection<IEObjectDescription> descriptions(Object target, Object criteria, int level) {
+ OptionType optionType = optionTypeFrom(criteria);
+ return super.descriptions(target, optionType.messageName(), level);
+ }
+
+ private OptionType optionTypeFrom(Object criteria) {
+ if (!(criteria instanceof OptionType))
+ throw new IllegalArgumentException("Search criteria should be OptionType");
+ return (OptionType) criteria;
+ }
+}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ExtendMessageSearchDelegate.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ExtendMessageSearchDelegate.java
new file mode 100644
index 0000000..2473fd2
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ExtendMessageSearchDelegate.java
@@ -0,0 +1,83 @@
+/*
+ * 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 java.util.Collections.emptySet;
+import static org.eclipse.xtext.resource.EObjectDescription.create;
+
+import com.google.eclipse.protobuf.model.util.ModelFinder;
+import com.google.eclipse.protobuf.protobuf.*;
+import com.google.inject.Inject;
+
+import org.eclipse.xtext.naming.QualifiedName;
+import org.eclipse.xtext.resource.IEObjectDescription;
+
+import java.util.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class ExtendMessageSearchDelegate implements SearchDelegate {
+
+ @Inject private LocalNamesProvider localNamesProvider;
+ @Inject private ModelFinder modelFinder;
+ @Inject private QualifiedNameDescriptions qualifiedNamesDescriptions;
+
+ @Override public boolean continueSearchOneLevelHigher(Object target) {
+ return target instanceof Message;
+ }
+
+ @Override public Collection<IEObjectDescription> fromProtoDescriptor(Import anImport, Object criteria) {
+ return emptySet();
+ }
+
+ @Override public Collection<IEObjectDescription> descriptions(Object target, Object criteria) {
+ String messageName = messageNameFrom(criteria);
+ if (!isExtendingOptionMessage(target, messageName)) return emptySet();
+ Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+ ExtendMessage extend = (ExtendMessage) target;
+ for (MessageElement e : extend.getElements()) {
+ if (!(e instanceof Property)) continue;
+ Property p = (Property) e;
+ descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(p));
+ }
+ return descriptions;
+ }
+
+ @Override public Collection<IEObjectDescription> descriptions(Object target, Object criteria, int level) {
+ String messageName = messageNameFrom(criteria);
+ if (!isExtendingOptionMessage(target, messageName)) return emptySet();
+ Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+ ExtendMessage extend = (ExtendMessage) target;
+ for (MessageElement e : extend.getElements()) {
+ if (!(e instanceof Property)) continue;
+ Property p = (Property) e;
+ List<QualifiedName> names = localNamesProvider.namesOf(p);
+ int nameCount = names.size();
+ for (int i = level; i < nameCount; i++) {
+ descriptions.add(create(names.get(i), p));
+ }
+ descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(p));
+ }
+ return descriptions;
+ }
+
+ private String messageNameFrom(Object criteria) {
+ if (!(criteria instanceof String))
+ throw new IllegalArgumentException("Search criteria should be String");
+ return (String) criteria;
+ }
+
+ private boolean isExtendingOptionMessage(Object o, String messageName) {
+ if (!(o instanceof ExtendMessage)) return false;
+ Message message = modelFinder.messageFrom((ExtendMessage) o);
+ if (message == null) return false;
+ return messageName.equals(message.getName());
+ }
+}
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 1e050c7..a387f2f 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,19 +8,21 @@
*/
package com.google.eclipse.protobuf.scoping;
-import static java.util.Collections.emptySet;
+import static com.google.eclipse.protobuf.scoping.OptionType.typeOf;
+import static java.util.Collections.*;
+import static org.eclipse.xtext.resource.EObjectDescription.create;
-import java.util.*;
+import com.google.eclipse.protobuf.model.util.*;
+import com.google.eclipse.protobuf.protobuf.*;
+import com.google.eclipse.protobuf.protobuf.Enum;
+import com.google.inject.*;
import org.eclipse.emf.ecore.*;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.impl.*;
-import com.google.eclipse.protobuf.model.util.*;
-import com.google.eclipse.protobuf.protobuf.*;
-import com.google.eclipse.protobuf.protobuf.Enum;
-import com.google.inject.Inject;
+import java.util.*;
/**
* Custom scoping description.
@@ -33,21 +35,23 @@
private static final boolean DO_NOT_IGNORE_CASE = false;
- @Inject private CustomOptionDescriptions customOptionDescriptions;
+ @Inject private CustomOptionSearchDelegate customOptionSearchDelegate;
@Inject private ProtoDescriptorProvider descriptorProvider;
@Inject private FieldOptions fieldOptions;
- @Inject private ModelFinder finder;
+ @Inject private ModelFinder modelFinder;
@Inject private LiteralDescriptions literalDescriptions;
@Inject private NativeOptionDescriptions nativeOptionDescriptions;
@Inject private Options options;
- @Inject private TypeDescriptions typeDescriptions;
+ @Inject private ScopeFinder scopeFinder;
+ @Inject private TypeSearchDelegate typeSearchDelegate;
+ @Inject private QualifiedNameDescriptions qualifiedNamesDescriptions;
@SuppressWarnings("unused")
public IScope scope_TypeRef_type(TypeRef typeRef, EReference reference) {
EObject c = typeRef.eContainer();
if (c instanceof Property) {
Property property = (Property) c;
- return createScope(typeDescriptions.types(property));
+ return createScope(scopeFinder.findScope(property, typeSearchDelegate, Type.class));
}
Set<IEObjectDescription> descriptions = emptySet();
return createScope(descriptions);
@@ -55,8 +59,8 @@
@SuppressWarnings("unused")
public IScope scope_MessageRef_type(MessageRef messageRef, EReference reference) {
- Protobuf root = finder.rootOf(messageRef);
- return createScope(typeDescriptions.messages(root));
+ Protobuf root = modelFinder.rootOf(messageRef);
+ return createScope(scopeFinder.findScope(root, typeSearchDelegate, Message.class));
}
@SuppressWarnings("unused")
@@ -65,7 +69,7 @@
Enum anEnum = null;
if (c instanceof DefaultValueFieldOption) {
EObject optionContainer = c.eContainer();
- if (optionContainer instanceof Property) anEnum = finder.enumTypeOf((Property) optionContainer);
+ if (optionContainer instanceof Property) anEnum = modelFinder.enumTypeOf((Property) optionContainer);
}
if (c instanceof NativeOption) {
ProtoDescriptor descriptor = descriptorProvider.primaryDescriptor();
@@ -88,7 +92,7 @@
if (c == null) c = fieldOptions.propertyFrom(option);
}
if (c instanceof Property) {
- anEnum = finder.enumTypeOf((Property) c);
+ anEnum = modelFinder.enumTypeOf((Property) c);
}
return createScope(literalDescriptions.literalsOf(anEnum));
}
@@ -106,35 +110,132 @@
}
if (c instanceof CustomOption) {
CustomOption option = (CustomOption) c;
- return createScope(customOptionDescriptions.properties(option));
+ return createScope(scopeFinder.findScope(option, customOptionSearchDelegate, typeOf(option)));
}
if (c instanceof CustomFieldOption) {
CustomFieldOption option = (CustomFieldOption) c;
- return createScope(customOptionDescriptions.properties(option));
+ return createScope(scopeFinder.findScope(option, customOptionSearchDelegate, typeOf(option)));
}
Set<IEObjectDescription> descriptions = emptySet();
return createScope(descriptions);
}
@SuppressWarnings("unused")
- public IScope scope_SimplePropertyRef_property(SimplePropertyRef propertyRef, EReference reference) {
+ public IScope scope_MessagePropertyRef_messageProperty(MessagePropertyRef propertyRef, EReference reference) {
EObject c = propertyRef.eContainer();
Property property = null;
if (c instanceof CustomOption) {
- CustomOption option = (CustomOption) c;
- property = options.propertyFrom(option);
+ final CustomOption option = (CustomOption) c;
+ property = referencedProperty(propertyRef, option.getOptionFields(), new Provider<Property>() {
+ @Override public Property get() {
+ return options.propertyFrom(option);
+ }
+ });
}
if (c instanceof CustomFieldOption) {
- CustomFieldOption option = (CustomFieldOption) c;
- property = fieldOptions.propertyFrom(option);
+ final CustomFieldOption option = (CustomFieldOption) c;
+ property = referencedProperty(propertyRef, option.getOptionFields(), new Provider<Property>() {
+ @Override public Property get() {
+ return fieldOptions.propertyFrom(option);
+ }
+ });
}
if (property != null) {
- return createScope(customOptionDescriptions.fields(property));
+ return createScope(fieldsInMessageContaining(property));
+ }
+ Set<IEObjectDescription> descriptions = emptySet();
+ return createScope(descriptions);
+ }
+
+ private Property referencedProperty(MessagePropertyRef ref, List<OptionField> fields, Provider<Property> provider) {
+ OptionField previous = null;
+ boolean isFirstField = true;
+ for (OptionField field : fields) {
+ if (field == ref) return (isFirstField) ? provider.get() : propertyFrom(previous);
+ previous = field;
+ isFirstField = false;
+ }
+ return null;
+ }
+
+ private Collection <IEObjectDescription> fieldsInMessageContaining(Property p) {
+ Message propertyType = modelFinder.messageTypeOf(p);
+ if (propertyType == null) return emptyList();
+ Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+ for (MessageElement e : propertyType.getElements()) {
+ if (!(e instanceof Property)) continue;
+ Property optionPropertyField = (Property) e;
+ descriptions.add(create(optionPropertyField.getName(), optionPropertyField));
+ }
+ return descriptions;
+ }
+
+ @SuppressWarnings("unused")
+ public IScope scope_ExtendMessagePropertyRef_extendMessageProperty(ExtendMessagePropertyRef propertyRef,
+ EReference reference) {
+ EObject c = propertyRef.eContainer();
+ Property property = null;
+ if (c instanceof CustomOption) {
+ final CustomOption option = (CustomOption) c;
+ property = referencedProperty(propertyRef, option.getOptionFields(), new Provider<Property>() {
+ @Override public Property get() {
+ return options.propertyFrom(option);
+ }
+ });
+ }
+ if (c instanceof CustomFieldOption) {
+ final CustomFieldOption option = (CustomFieldOption) c;
+ property = referencedProperty(propertyRef, option.getOptionFields(), new Provider<Property>() {
+ @Override public Property get() {
+ return fieldOptions.propertyFrom(option);
+ }
+ });
+ }
+ if (property != null) {
+ return createScope(fieldsInExtendedVersionOfMessageContaining(property));
}
Set<IEObjectDescription> descriptions = emptySet();
return createScope(descriptions);
}
+ private Property referencedProperty(ExtendMessagePropertyRef ref, List<OptionField> fields, Provider<Property> provider) {
+ OptionField previous = null;
+ boolean isFirstField = true;
+ for (OptionField field : fields) {
+ if (field == ref) return (isFirstField) ? provider.get() : propertyFrom(previous);
+ previous = field;
+ isFirstField = false;
+ }
+ return null;
+ }
+
+ private Collection <IEObjectDescription> fieldsInExtendedVersionOfMessageContaining(Property p) {
+ Message propertyType = modelFinder.messageTypeOf(p);
+ if (propertyType == null) return emptyList();
+ Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+ for (ExtendMessage extend : modelFinder.extensionsOf(propertyType)) {
+ for (MessageElement e : extend.getElements()) {
+ if (!(e instanceof Property)) continue;
+ Property optionPropertyField = (Property) e;
+ descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(optionPropertyField));
+ descriptions.add(create(optionPropertyField.getName(), optionPropertyField));
+ }
+ }
+ return descriptions;
+ }
+
+ private Property propertyFrom(OptionField field) {
+ if (field instanceof MessagePropertyRef) {
+ MessagePropertyRef ref = (MessagePropertyRef) field;
+ return ref.getMessageProperty();
+ }
+ if (field instanceof ExtendMessagePropertyRef) {
+ ExtendMessagePropertyRef ref = (ExtendMessagePropertyRef) field;
+ return ref.getExtendMessageProperty();
+ }
+ return null;
+ }
+
private static IScope createScope(Iterable<IEObjectDescription> descriptions) {
return new SimpleScope(descriptions, DO_NOT_IGNORE_CASE);
}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ScopeFinder.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ScopeFinder.java
new file mode 100644
index 0000000..7b921f4
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ScopeFinder.java
@@ -0,0 +1,123 @@
+/*
+ * 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 java.util.Collections.emptyList;
+import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents;
+
+import com.google.eclipse.protobuf.model.util.*;
+import com.google.eclipse.protobuf.parser.NonProto2;
+import com.google.eclipse.protobuf.protobuf.*;
+import com.google.eclipse.protobuf.protobuf.Package;
+import com.google.inject.Inject;
+
+import org.eclipse.emf.common.util.TreeIterator;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.*;
+import org.eclipse.xtext.resource.IEObjectDescription;
+
+import java.util.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class ScopeFinder {
+
+ @Inject private ModelFinder finder;
+ @Inject private Imports imports;
+ @Inject private Packages packages;
+ @Inject private Resources resources;
+
+ Collection<IEObjectDescription> findScope(EObject target, SearchDelegate delegate, Object criteria) {
+ Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+ EObject current = target.eContainer();
+ while (current != null) {
+ descriptions.addAll(local(current, delegate, criteria));
+ current = current.eContainer();
+ }
+ Protobuf root = finder.rootOf(target);
+ descriptions.addAll(imported(root, delegate, criteria));
+ return descriptions;
+ }
+
+ Collection<IEObjectDescription> findScope(Protobuf root, SearchDelegate delegate, Object criteria) {
+ Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+ descriptions.addAll(local(root, delegate, criteria));
+ descriptions.addAll(imported(root, delegate, criteria));
+ return descriptions;
+ }
+
+ private Collection<IEObjectDescription> local(EObject root, SearchDelegate delegate, Object criteria) {
+ return local(root, delegate, criteria, 0);
+ }
+
+ private Collection<IEObjectDescription> local(EObject root, SearchDelegate delegate, Object criteria, int level) {
+ List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
+ for (EObject element : root.eContents()) {
+ descriptions.addAll(delegate.descriptions(element, criteria, level));
+ if (delegate.continueSearchOneLevelHigher(element)) {
+ descriptions.addAll(local(element, delegate, criteria, level + 1));
+ }
+ }
+ return descriptions;
+ }
+
+ private Collection<IEObjectDescription> imported(Protobuf root, SearchDelegate delegate, Object criteria) {
+ List<Import> allImports = finder.importsIn(root);
+ if (allImports.isEmpty()) return emptyList();
+ ResourceSet resourceSet = root.eResource().getResourceSet();
+ return imported(allImports, finder.packageOf(root), resourceSet, delegate, criteria);
+ }
+
+ private Collection<IEObjectDescription> imported(List<Import> allImports, Package aPackage,
+ ResourceSet resourceSet, SearchDelegate delegate, Object criteria) {
+ List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
+ for (Import anImport : allImports) {
+ if (imports.isImportingDescriptor(anImport)) {
+ descriptions.addAll(delegate.fromProtoDescriptor(anImport, criteria));
+ continue;
+ }
+ Resource importedResource = resources.importedResource(anImport, resourceSet);
+ Protobuf rootOfImported = finder.rootOf(importedResource);
+ if (rootOfImported instanceof NonProto2) continue;
+ if (rootOfImported != null) {
+ descriptions.addAll(publicImported(rootOfImported, delegate, criteria));
+ if (arePackagesRelated(aPackage, rootOfImported)) {
+ descriptions.addAll(local(rootOfImported, delegate, criteria));
+ continue;
+ }
+ }
+ descriptions.addAll(local(importedResource, delegate, criteria));
+ }
+ return descriptions;
+ }
+
+ private Collection<IEObjectDescription> publicImported(Protobuf root, SearchDelegate delegate, Object criteria) {
+ List<Import> allImports = finder.publicImportsIn(root);
+ if (allImports.isEmpty()) return emptyList();
+ ResourceSet resourceSet = root.eResource().getResourceSet();
+ return imported(allImports, finder.packageOf(root), resourceSet, delegate, criteria);
+ }
+
+ private boolean arePackagesRelated(Package aPackage, EObject root) {
+ Package p = finder.packageOf(root);
+ return packages.areRelated(aPackage, p);
+ }
+
+ private Collection<IEObjectDescription> local(Resource resource, SearchDelegate delegate, Object criteria) {
+ List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
+ TreeIterator<Object> contents = getAllContents(resource, true);
+ while (contents.hasNext()) {
+ Object next = contents.next();
+ descriptions.addAll(delegate.descriptions(next, criteria));
+ // TODO verify that call to 'importedNamesProvider.namesOf' is not necessary
+ }
+ return descriptions;
+ }
+}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/SearchDelegate.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/SearchDelegate.java
new file mode 100644
index 0000000..a8dd4d0
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/SearchDelegate.java
@@ -0,0 +1,29 @@
+/*
+ * 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 com.google.eclipse.protobuf.protobuf.Import;
+
+import org.eclipse.xtext.resource.IEObjectDescription;
+
+import java.util.Collection;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+interface SearchDelegate {
+
+ boolean continueSearchOneLevelHigher(Object target);
+
+ Collection<IEObjectDescription> fromProtoDescriptor(Import anImport, Object criteria);
+
+ Collection<IEObjectDescription> descriptions(Object target, Object criteria);
+
+ Collection<IEObjectDescription> descriptions(Object target, Object criteria, int level);
+}
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
deleted file mode 100644
index 835d74b..0000000
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeDescriptions.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * 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 java.util.Collections.emptyList;
-import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents;
-import static org.eclipse.xtext.resource.EObjectDescription.create;
-
-import java.util.*;
-
-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 com.google.eclipse.protobuf.model.util.*;
-import com.google.eclipse.protobuf.parser.NonProto2;
-import com.google.eclipse.protobuf.protobuf.*;
-import com.google.eclipse.protobuf.protobuf.Package;
-import com.google.inject.Inject;
-
-/**
- * @author alruiz@google.com (Alex Ruiz)
- */
-class TypeDescriptions {
-
- @Inject private ProtoDescriptorProvider descriptorProvider;
- @Inject private ModelFinder finder;
- @Inject private Imports imports;
- @Inject private LocalNamesProvider localNamesProvider;
- @Inject private Packages packages;
- @Inject private QualifiedNameDescriptions qualifiedNamesDescriptions;
- @Inject private Resources resources;
-
- Collection<IEObjectDescription> types(Property property) {
- Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
- EObject current = property.eContainer();
- Class<Type> targetType = Type.class;
- while (current != null) {
- descriptions.addAll(local(current, targetType));
- current = current.eContainer();
- }
- Protobuf root = finder.rootOf(property);
- descriptions.addAll(imported(root, targetType));
- return descriptions;
- }
-
- Collection<IEObjectDescription> messages(Protobuf root) {
- Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
- Class<Message> targetType = Message.class;
- descriptions.addAll(local(root, targetType));
- descriptions.addAll(imported(root, targetType));
- return descriptions;
- }
-
- private <T extends Type> Collection<IEObjectDescription> local(EObject root, Class<T> targetType) {
- return local(root, targetType, 0);
- }
-
- private <T extends Type> Collection<IEObjectDescription> local(EObject root, Class<T> targetType, int level) {
- List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
- for (EObject element : root.eContents()) {
- if (!targetType.isInstance(element)) continue;
- List<QualifiedName> names = localNamesProvider.namesOf(element);
- int nameCount = names.size();
- for (int i = level; i < nameCount; i++) {
- descriptions.add(create(names.get(i), element));
- }
- descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(element));
- // TODO investigate if groups can have messages, and if so, add those messages to the scope.
- if (element instanceof Message) {
- descriptions.addAll(local(element, targetType, level + 1));
- }
- }
- return descriptions;
- }
-
- private <T extends Type> Collection<IEObjectDescription> imported(Protobuf root, Class<T> targetType) {
- List<Import> allImports = finder.importsIn(root);
- if (allImports.isEmpty()) return emptyList();
- ResourceSet resourceSet = root.eResource().getResourceSet();
- return imported(allImports, finder.packageOf(root), resourceSet, targetType);
- }
-
- private <T extends Type> Collection<IEObjectDescription> imported(List<Import> allImports, Package aPackage,
- ResourceSet resourceSet, Class<T> targetType) {
- List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
- for (Import anImport : allImports) {
- if (imports.isImportingDescriptor(anImport)) {
- descriptions.addAll(allNative(anImport, targetType));
- continue;
- }
- Resource importedResource = resources.importedResource(anImport, resourceSet);
- Protobuf rootOfImported = finder.rootOf(importedResource);
- if (rootOfImported instanceof NonProto2) continue;
- if (rootOfImported != null) {
- descriptions.addAll(publicImported(rootOfImported, targetType));
- if (arePackagesRelated(aPackage, rootOfImported)) {
- descriptions.addAll(local(rootOfImported, targetType));
- continue;
- }
- }
- descriptions.addAll(local(importedResource, targetType));
- }
- return descriptions;
- }
-
- private <T extends Type> Collection<IEObjectDescription> allNative(Import anImport, Class<T> targetType) {
- List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
- ProtoDescriptor descriptor = descriptorProvider.descriptor(anImport.getImportURI());
- for (Type t : descriptor.allTypes()) {
- if (!targetType.isInstance(t)) continue;
- T type = targetType.cast(t);
- descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(type));
- }
- return descriptions;
- }
-
- private <T extends Type> Collection<IEObjectDescription> publicImported(Protobuf root, Class<T> targetType) {
- List<Import> allImports = finder.publicImportsIn(root);
- if (allImports.isEmpty()) return emptyList();
- ResourceSet resourceSet = root.eResource().getResourceSet();
- return imported(allImports, finder.packageOf(root), resourceSet, targetType);
- }
-
- private boolean arePackagesRelated(Package aPackage, EObject root) {
- Package p = finder.packageOf(root);
- return packages.areRelated(aPackage, p);
- }
-
- private <T extends Type> Collection<IEObjectDescription> local(Resource resource, Class<T> targetType) {
- List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
- TreeIterator<Object> contents = getAllContents(resource, true);
- while (contents.hasNext()) {
- Object next = contents.next();
- if (!targetType.isInstance(next)) continue;
- T type = targetType.cast(next);
- descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(type));
- // TODO verify that call to 'importedNamesProvider.namesOf' is not necessary
- }
- return descriptions;
- }
-}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeSearchDelegate.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeSearchDelegate.java
new file mode 100644
index 0000000..493803b
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeSearchDelegate.java
@@ -0,0 +1,73 @@
+/*
+ * 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 java.util.Collections.emptySet;
+import static org.eclipse.xtext.resource.EObjectDescription.create;
+
+import com.google.eclipse.protobuf.protobuf.*;
+import com.google.inject.Inject;
+
+import org.eclipse.xtext.naming.QualifiedName;
+import org.eclipse.xtext.resource.IEObjectDescription;
+
+import java.util.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class TypeSearchDelegate implements SearchDelegate {
+
+ @Inject private ProtoDescriptorProvider descriptorProvider;
+ @Inject private LocalNamesProvider localNamesProvider;
+ @Inject private QualifiedNameDescriptions qualifiedNamesDescriptions;
+
+ @Override public boolean continueSearchOneLevelHigher(Object target) {
+ return target instanceof Message;
+ }
+
+ @Override public Collection<IEObjectDescription> fromProtoDescriptor(Import anImport, Object criteria) {
+ Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+ Class<? extends Type> targetType = targetTypeFrom(criteria);
+ ProtoDescriptor descriptor = descriptorProvider.descriptor(anImport.getImportURI());
+ for (Type type : descriptor.allTypes()) {
+ if (!targetType.isInstance(type)) continue;
+ descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(type));
+ }
+ return descriptions;
+ }
+
+ @Override public Collection<IEObjectDescription> descriptions(Object target, Object criteria) {
+ Class<? extends Type> targetType = targetTypeFrom(criteria);
+ if (!targetType.isInstance(target)) return emptySet();
+ Type type = targetType.cast(target);
+ return qualifiedNamesDescriptions.qualifiedNames(type);
+ }
+
+ @Override public Collection<IEObjectDescription> descriptions(Object target, Object criteria, int level) {
+ Class<? extends Type> targetType = targetTypeFrom(criteria);
+ if (!targetType.isInstance(target)) return emptySet();
+ Type type = targetType.cast(target);
+ Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+ List<QualifiedName> names = localNamesProvider.namesOf(type);
+ int nameCount = names.size();
+ for (int i = level; i < nameCount; i++) {
+ descriptions.add(create(names.get(i), type));
+ }
+ descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(type));
+ return descriptions;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Class<? extends Type> targetTypeFrom(Object criteria) {
+ if (!(criteria instanceof Class))
+ throw new IllegalArgumentException("Search criteria should be Class<? extends Type>");
+ return (Class<? extends Type>) criteria;
+ }
+}