In progress: [Issue 161] package scope resolution.
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/IntersectedPackageDescriptions_createFqn_Test.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/IntersectedPackageDescriptions_createFqn_Test.java
new file mode 100644
index 0000000..f026fd0
--- /dev/null
+++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/IntersectedPackageDescriptions_createFqn_Test.java
@@ -0,0 +1,41 @@
+/*
+ * 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.Arrays.asList;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+import org.eclipse.xtext.naming.QualifiedName;
+import org.junit.*;
+
+import java.util.List;
+
+/**
+ * Tests for <code>{@link IntersectedPackageDescriptions#createFqn(String, List)}</code>
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class IntersectedPackageDescriptions_createFqn_Test {
+
+ private String name;
+ private List<String> packageFqn;
+ private IntersectedPackageDescriptions descriptions;
+
+ @Before public void setUp() {
+ name = "Person";
+ packageFqn = asList("com", "google", "test");
+ descriptions = new IntersectedPackageDescriptions();
+ }
+
+ @Test public void should_concatenate_name_and_package_fqn() {
+ QualifiedName fqn = descriptions.createFqn(name, packageFqn);
+ assertThat(fqn.toString(), equalTo("com.google.test.Person"));
+ }
+}
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/PackageIntersection_intersection_Test.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/PackageIntersection_intersection_Test.java
index 1fe9675..915e11f 100644
--- a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/PackageIntersection_intersection_Test.java
+++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/PackageIntersection_intersection_Test.java
@@ -61,4 +61,11 @@
List<String> segments = intersection.intersection(p1, p2);
assertTrue(segments.isEmpty());
}
+
+ @Test public void should_return_empty_list_when_packages_are_different_and_first_name_of_first_package_is_shorter() {
+ when(p1.getName()).thenReturn("proto");
+ when(p2.getName()).thenReturn("project.shared");
+ List<String> segments = intersection.intersection(p1, p2);
+ assertTrue(segments.isEmpty());
+ }
}
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 81aeed8..b6783e7 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
@@ -20,6 +20,7 @@
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.xtext.parser.IParseResult;
import org.eclipse.xtext.resource.XtextResource;
import java.util.*;
@@ -161,8 +162,11 @@
*/
public Protobuf rootOf(Resource resource) {
if (resource instanceof XtextResource) {
- EObject root = ((XtextResource) resource).getParseResult().getRootASTElement();
- return (Protobuf) root;
+ IParseResult parseResult = ((XtextResource) resource).getParseResult();
+ if (parseResult != null) {
+ EObject root = parseResult.getRootASTElement();
+ return (Protobuf) root;
+ }
}
TreeIterator<Object> contents = getAllContents(resource, true);
if (contents.hasNext()) {
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/AstWalker.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/AstWalker.java
index f9031ea..74e7afc 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/AstWalker.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/AstWalker.java
@@ -84,6 +84,7 @@
continue;
}
Resource imported = resources.importedResource(anImport, resourceSet);
+ if (imported == null) continue;
Protobuf rootOfImported = modelFinder.rootOf(imported);
if (rootOfImported instanceof NonProto2) continue;
if (rootOfImported != null) {
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionScopeFinder.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionScopeFinder.java
index 3df57fa..07dc9c0 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionScopeFinder.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionScopeFinder.java
@@ -31,7 +31,8 @@
@Inject private ModelFinder modelFinder;
@Inject private QualifiedNameDescriptions qualifiedNamesDescriptions;
- @Override public Collection<IEObjectDescription> imported(Package fromImporter, Package fromImported, Object target, Object criteria) {
+ @Override public Collection<IEObjectDescription> imported(Package fromImporter, Package fromImported, Object target,
+ Object criteria) {
OptionType optionType = optionTypeFrom(criteria);
if (!isExtendingOptionMessage(target, optionType)) return emptySet();
Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/IntersectedPackageDescriptions.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/IntersectedPackageDescriptions.java
new file mode 100644
index 0000000..64089ed
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/IntersectedPackageDescriptions.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.scoping;
+
+import static org.eclipse.xtext.resource.EObjectDescription.create;
+import static org.eclipse.xtext.util.SimpleAttributeResolver.newResolver;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.naming.QualifiedName;
+import org.eclipse.xtext.resource.*;
+
+import java.util.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class IntersectedPackageDescriptions {
+
+ private final Function<EObject, String> resolver = newResolver(String.class, "name");
+
+ IEObjectDescription description(EObject e, List<String> packageFqn) {
+ if (packageFqn.isEmpty()) return null;
+ String name = resolver.apply(e);
+ QualifiedName fqn = createFqn(name, packageFqn);
+ return create(fqn, e);
+ }
+
+ @VisibleForTesting
+ QualifiedName createFqn(String name, List<String> packageFqn) {
+ List<String> nameSegments = new ArrayList<String>(packageFqn);
+ nameSegments.add(name);
+ return QualifiedName.create(nameSegments.toArray(new String[nameSegments.size()]));
+ }
+}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/NativeOptionDescriptions.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/NativeOptionDescriptions.java
index 1a7bf63..44f0eca 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/NativeOptionDescriptions.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/NativeOptionDescriptions.java
@@ -26,19 +26,19 @@
@Inject private ProtoDescriptorProvider descriptorProvider;
- Collection <IEObjectDescription> properties(NativeOption option) {
- return allProperties(option);
+ Collection <IEObjectDescription> sources(NativeOption option) {
+ return allSources(option);
}
- Collection <IEObjectDescription> properties(NativeFieldOption option) {
- return allProperties(option);
+ Collection <IEObjectDescription> sources(NativeFieldOption option) {
+ return allSources(option);
}
- private Collection <IEObjectDescription> allProperties(EObject option) {
+ private Collection <IEObjectDescription> allSources(EObject option) {
ProtoDescriptor descriptor = descriptorProvider.primaryDescriptor();
- Collection<MessageField> fields = descriptor.availableOptionsFor(option.eContainer());
- if (fields.isEmpty()) return emptyList();
- return describe(fields);
+ Collection<MessageField> optionSources = descriptor.availableOptionsFor(option.eContainer());
+ if (optionSources.isEmpty()) return emptyList();
+ return describe(optionSources);
}
private Collection<IEObjectDescription> describe(Collection<MessageField> fields) {
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/PackageIntersection.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/PackageIntersection.java
index a98b316..ae498e7 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/PackageIntersection.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/PackageIntersection.java
@@ -25,7 +25,7 @@
@Inject private final IQualifiedNameConverter converter = new IQualifiedNameConverter.DefaultImpl();
List<String> intersection(Package p1, Package p2) {
- if (p2 == null) return null;
+ if (p1 == null || p2 == null) return emptyList();
return intersection(converter.toQualifiedName(p1.getName()), converter.toQualifiedName(p2.getName()));
}
@@ -37,12 +37,16 @@
List<String> intersection = new ArrayList<String>();
int n1Count = n1.size();
int n2Count = n2.size();
- boolean differenceFound = false;
+ int start = -1;
for (int i = 0; (i < n1Count && i < n2Count); i++) {
- String n2Segment = n2.get(i);
- if (differenceFound || !n1.get(i).equals(n2Segment)) {
- differenceFound = true;
- intersection.add(n2Segment);
+ if (!n1.get(i).equals(n2.get(i))) {
+ start = i;
+ break;
+ }
+ }
+ if (start >= 0) {
+ for (int i = start; i < n2Count; i++) {
+ intersection.add(n2.get(i));
}
}
if (intersection.equals(n2)) return emptyList();
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 010a499..05da44b 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
@@ -48,9 +48,13 @@
@SuppressWarnings("unused")
public IScope scope_ComplexTypeLink_target(ComplexTypeLink link, EReference r) {
- EObject c = link.eContainer();
- if (c instanceof MessageField) {
- return createScope(findScope((MessageField) c));
+ try {
+ EObject c = link.eContainer();
+ if (c instanceof MessageField) {
+ return createScope(findScope((MessageField) c));
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
}
Set<IEObjectDescription> descriptions = emptySet();
return createScope(descriptions);
@@ -106,11 +110,11 @@
EObject c = source.eContainer();
if (c instanceof NativeOption) {
NativeOption option = (NativeOption) c;
- return createScope(nativeOptionDescriptions.properties(option));
+ return createScope(nativeOptionDescriptions.sources(option));
}
if (c instanceof NativeFieldOption) {
NativeFieldOption option = (NativeFieldOption) c;
- return createScope(nativeOptionDescriptions.properties(option));
+ return createScope(nativeOptionDescriptions.sources(option));
}
if (c instanceof CustomOption) {
CustomOption option = (CustomOption) c;
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeScopeFinder.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeScopeFinder.java
index 6a483af..e37d3b8 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeScopeFinder.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeScopeFinder.java
@@ -27,15 +27,22 @@
*/
class TypeScopeFinder implements ScopeFinder {
- @Inject private PackageIntersection packageIntersection;
+ @Inject private IntersectedPackageDescriptions intersectedPackageDescriptions;
@Inject private ProtoDescriptorProvider descriptorProvider;
@Inject private LocalNamesProvider localNamesProvider;
+ @Inject private PackageIntersection packageIntersection;
@Inject private QualifiedNameDescriptions qualifiedNamesDescriptions;
- @Override public Collection<IEObjectDescription> imported(Package fromImporter, Package fromImported, Object target, Object criteria) {
+ @Override public Collection<IEObjectDescription> imported(Package fromImporter, Package fromImported, Object target,
+ Object criteria) {
if (!isInstance(target, criteria)) return emptySet();
+ Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
EObject e = (EObject) target;
- return qualifiedNamesDescriptions.qualifiedNames(e);
+ descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(e));
+ List<String> intersection = packageIntersection.intersection(fromImporter, fromImported);
+ IEObjectDescription d = intersectedPackageDescriptions.description(e, intersection);
+// if (d != null) descriptions.add(d);
+ return descriptions;
}
@Override public Collection<IEObjectDescription> inDescriptor(Import anImport, Object criteria) {