Fixed: [ Issue 58 ] protobuf-dt expects imports and options to be grouped together https://code.google.com/p/protobuf-dt/issues/detail?id=58
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/util/Finder.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/util/Finder.java index 31583dc..b530ec6 100644 --- a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/util/Finder.java +++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/util/Finder.java
@@ -33,7 +33,7 @@ } public static Option findOption(String name, Protobuf root) { - for (Option option : root.getOptions()) + for (Option option : getAllContentsOfType(root, Option.class)) if (name.equals(option.getName())) return option; return null; }
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/util/ProtobufElementFinder_importsIn_Test.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/util/ProtobufElementFinder_importsIn_Test.java new file mode 100644 index 0000000..bc73f66 --- /dev/null +++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/util/ProtobufElementFinder_importsIn_Test.java
@@ -0,0 +1,58 @@ +/* + * 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.util; + +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.assertThat; + +import java.util.List; + +import org.junit.*; + +import com.google.eclipse.protobuf.junit.core.XtextRule; +import com.google.eclipse.protobuf.protobuf.*; + +/** + * Tests for <code>{@link ProtobufElementFinder#importsIn(Protobuf)}</code>. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class ProtobufElementFinder_importsIn_Test { + + @Rule public XtextRule xtext = new XtextRule(); + + private ProtobufElementFinder finder; + + @Before public void setUp() { + finder = xtext.getInstanceOf(ProtobufElementFinder.class); + } + + @Test public void should_return_all_imports() { + StringBuilder proto = new StringBuilder(); + proto.append("import \"luke.proto\"") + .append("import \"leia.proto\""); + Protobuf root = xtext.parse(proto); + List<Import> allImports = finder.importsIn(root); + assertThat(allImports.size(), equalTo(2)); + assertThat(allImports.get(0).getImportURI(), equalTo("luke.proto")); + assertThat(allImports.get(1).getImportURI(), equalTo("leia.proto")); + } + + @Test public void should_return_empty_if_no_imports_found() { + StringBuilder proto = new StringBuilder(); + proto.append("enum PhoneType {") + .append(" MOBILE = 0; ") + .append(" HOME = 1; ") + .append(" WORK = 2; ") + .append("} "); + Protobuf root = xtext.parse(proto); + List<Import> allImports = finder.importsIn(root); + assertThat(allImports.size(), equalTo(0)); + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/syntaxcoloring/ProtobufSemanticHighlightingCalculator.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/syntaxcoloring/ProtobufSemanticHighlightingCalculator.java index 5a730de..043be93 100644 --- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/syntaxcoloring/ProtobufSemanticHighlightingCalculator.java +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/syntaxcoloring/ProtobufSemanticHighlightingCalculator.java
@@ -39,25 +39,15 @@ } private void highlightAllNames(Protobuf protobuf, IHighlightedPositionAcceptor acceptor, String highlightId) { - highlightPackageName(protobuf, acceptor, highlightId); - highlightFileOptionNames(protobuf, acceptor, highlightId); highlightElementNames(protobuf, acceptor, highlightId); } - private void highlightPackageName(Protobuf protobuf, IHighlightedPositionAcceptor acceptor, String highlightId) { - Package aPackage = protobuf.getPackage(); - if (aPackage == null) return; - highlightName(aPackage, acceptor, highlightId); - } - - private void highlightFileOptionNames(Protobuf protobuf, IHighlightedPositionAcceptor acceptor, String highlightId) { - for (Option option : protobuf.getOptions()) { - highlightName(option, acceptor, highlightId); - } - } - private void highlightElementNames(Protobuf protobuf, IHighlightedPositionAcceptor acceptor, String highlightId) { for (ProtobufElement element : protobuf.getElements()) { + if (element instanceof Package || element instanceof Option) { + highlightName(element, acceptor, highlightId); + continue; + } if (element instanceof Type) { highlightName(element, acceptor, highlightId); if (element instanceof Message) highlightElementNames((Message) element, acceptor, highlightId);
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/outline/ProtobufOutlineTreeProvider.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/outline/ProtobufOutlineTreeProvider.java index a7c6603..7294426 100644 --- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/outline/ProtobufOutlineTreeProvider.java +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/outline/ProtobufOutlineTreeProvider.java
@@ -8,19 +8,13 @@ */ package com.google.eclipse.protobuf.ui.outline; -import static com.google.eclipse.protobuf.protobuf.ProtobufPackage.Literals.*; -import static com.google.eclipse.protobuf.ui.outline.Messages.*; - -import java.util.ArrayList; -import java.util.List; +import java.util.*; import org.eclipse.emf.ecore.EObject; import org.eclipse.xtext.ui.editor.outline.IOutlineNode; -import org.eclipse.xtext.ui.editor.outline.impl.DefaultOutlineTreeProvider; -import org.eclipse.xtext.ui.editor.outline.impl.DocumentRootNode; +import org.eclipse.xtext.ui.editor.outline.impl.*; import com.google.eclipse.protobuf.protobuf.*; -import com.google.eclipse.protobuf.protobuf.Package; /** * Customization of the default outline structure. @@ -30,13 +24,13 @@ public class ProtobufOutlineTreeProvider extends DefaultOutlineTreeProvider { private static final List<Class<? extends EObject>> IGNORED_ELEMENT_TYPES = new ArrayList<Class<? extends EObject>>(); - + static { IGNORED_ELEMENT_TYPES.add(BooleanRef.class); IGNORED_ELEMENT_TYPES.add(FieldOption.class); IGNORED_ELEMENT_TYPES.add(MessageReference.class); } - + boolean _isLeaf(Option o) { return true; } @@ -46,18 +40,18 @@ } protected void _createChildren(DocumentRootNode parentNode, Protobuf protobuf) { - Package aPackage = protobuf.getPackage(); - if (aPackage != null) { - createNode(parentNode, aPackage); - } - if (!protobuf.getImports().isEmpty()) { - createEStructuralFeatureNode(parentNode, protobuf, PROTOBUF__IMPORTS, - labelProvider.getImage("imports"), importDeclarations, false); - } - if (!protobuf.getOptions().isEmpty()) { - createEStructuralFeatureNode(parentNode, protobuf, PROTOBUF__OPTIONS, - labelProvider.getImage("options"), optionDeclarations, false); - } +// Package aPackage = protobuf.getPackage(); +// if (aPackage != null) { +// createNode(parentNode, aPackage); +// } +// if (!protobuf.getImports().isEmpty()) { +// createEStructuralFeatureNode(parentNode, protobuf, PROTOBUF__IMPORTS, +// labelProvider.getImage("imports"), importDeclarations, false); +// } +// if (!protobuf.getOptions().isEmpty()) { +// createEStructuralFeatureNode(parentNode, protobuf, PROTOBUF__OPTIONS, +// labelProvider.getImage("options"), optionDeclarations, false); +// } for (ProtobufElement e : protobuf.getElements()) { createNode(parentNode, e); } @@ -67,7 +61,7 @@ if (isIgnored(modelElement)) return; super.createNode(parent, modelElement); } - + private boolean isIgnored(EObject modelElement) { for (Class<? extends EObject> ignoredType : IGNORED_ELEMENT_TYPES) if (ignoredType.isInstance(modelElement)) return true;
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 303bc4a..d27a97b 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
@@ -16,11 +16,13 @@ Protobuf: (syntax=Syntax)? - ((package=Package)? & (imports+=Import)* & (options+=Option)*) (elements+=ProtobufElement)*; Syntax: 'syntax' '=' name=STRING ';'; + +ProtobufElement: + Package | Import | Option | Type | ExtendMessage | Service; Package: 'package' name=QualifiedName ';'; @@ -34,9 +36,6 @@ Option: 'option' name=Name '=' value=ValueRef ';'; -ProtobufElement: - Type | ExtendMessage | Service; - Type: Message | Enum;
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 f4a09d7..0798fb2 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
@@ -14,14 +14,10 @@ import java.util.*; -import org.eclipse.emf.common.util.TreeIterator; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EReference; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.resource.ResourceSet; -import org.eclipse.xtext.naming.IQualifiedNameProvider; -import org.eclipse.xtext.naming.QualifiedName; +import org.eclipse.emf.common.util.*; +import org.eclipse.emf.ecore.*; +import org.eclipse.emf.ecore.resource.*; +import org.eclipse.xtext.naming.*; import org.eclipse.xtext.resource.IEObjectDescription; import org.eclipse.xtext.scoping.IScope; import org.eclipse.xtext.scoping.impl.*; @@ -99,7 +95,7 @@ private <T extends Type> Collection<IEObjectDescription> importedTypes(Protobuf root, Class<T> targetType) { ResourceSet resourceSet = root.eResource().getResourceSet(); List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>(); - for (Import anImport : root.getImports()) { + for (Import anImport : finder.importsIn(root)) { URI importUri = createURI(uriResolver.apply(anImport)); Resource imported = resourceSet.getResource(importUri, true); descriptions.addAll(innerTypes(imported, targetType));
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 952cdf0..571f197 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
@@ -8,6 +8,10 @@ */ package com.google.eclipse.protobuf.util; +import static java.util.Collections.unmodifiableList; + +import java.util.*; + import org.eclipse.emf.ecore.EObject; import com.google.eclipse.protobuf.protobuf.*; @@ -56,17 +60,34 @@ * package. */ public Package packageOf(EObject o) { - return rootOf(o).getPackage(); + Protobuf root = rootOf(o); + for (ProtobufElement e : root.getElements()) { + if (e instanceof Package) return (Package) e; + } + return null; } /** - * Returns the root element of the proto file containing the given object. - * @param o the given object. - * @return the root element of the proto file containing the given object. + * Returns the root element of the proto file containing the given element. + * @param o the given element. + * @return the root element of the proto file containing the given element. */ public Protobuf rootOf(EObject o) { EObject current = o; while (!(current instanceof Protobuf)) current = current.eContainer(); return (Protobuf) current; } + + /** + * Returns all the import definitions in the given proto. + * @param root the given proto. + * @return all the import definitions in the given proto. + */ + public List<Import> importsIn(Protobuf root) { + List<Import> imports = new ArrayList<Import>(); + for (ProtobufElement e : root.getElements()) { + if (e instanceof Import) imports.add((Import) e); + } + return unmodifiableList(imports); + } }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/Messages.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/Messages.java index 93dee55..cbd6fa0 100644 --- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/Messages.java +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/Messages.java
@@ -22,6 +22,7 @@ public static String fieldNumbersMustBePositive; public static String importNotFound; public static String missingFieldNumber; + public static String multiplePackages; public static String unrecognizedSyntaxIdentifier; static {
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/Messages.properties b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/Messages.properties index 4cf6b11..dbb5a26 100644 --- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/Messages.properties +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/Messages.properties
@@ -5,4 +5,5 @@ fieldNumbersMustBePositive = Field numbers must be positive integers. importNotFound = Import \"%s\" was not found. missingFieldNumber = Missing field number. +multiplePackages = Multiple package definitions. unrecognizedSyntaxIdentifier = Unrecognized syntax identifier \"%s\". This parser only recognizes \"proto2\".
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufJavaValidator.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufJavaValidator.java index baca753..22a6323 100644 --- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufJavaValidator.java +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufJavaValidator.java
@@ -15,11 +15,11 @@ import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; -import org.eclipse.xtext.naming.IQualifiedNameProvider; -import org.eclipse.xtext.naming.QualifiedName; +import org.eclipse.xtext.naming.*; import org.eclipse.xtext.validation.Check; import com.google.eclipse.protobuf.protobuf.*; +import com.google.eclipse.protobuf.protobuf.Package; import com.google.inject.Inject; /** @@ -73,6 +73,18 @@ error(msg, FIELD__INDEX); } + @Check public void checkOnlyOnePackageDefinition(Package aPackage) { + boolean firstFound = false; + Protobuf root = (Protobuf) aPackage.eContainer(); + for (ProtobufElement e : root.getElements()) { + if (e == aPackage) { + if (firstFound) error(multiplePackages, PACKAGE__NAME); + return; + } + if (e instanceof Package && !firstFound) firstFound = true; + } + } + private boolean isNameNull(Field field) { return field.getName() == null; }