Initial support for "oneof" keyword for internal testing
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 41f1d91..57722aa 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
@@ -50,7 +50,7 @@
'}' (';')?;
MessageElement:
- Option | Extensions | ComplexType | MessageField | TypeExtension;
+ Option | Extensions | ComplexType | MessageField | TypeExtension | OneOf;
Range:
from=LONG ('to' to=RangeMax)?;
@@ -66,6 +66,14 @@
GroupElement:
Option | IndexedElement | ComplexType | TypeExtension | Extensions;
+
+OneOf:
+ 'oneof' name=Name '{'
+ elements+=OneOfElement*
+ '}' (';')?;
+
+OneOfElement returns MessageElement:
+ Extensions | UnmodifiedMessageField;
Extensions:
'extensions' ranges+=Range (',' ranges+=Range)* (';')+;
@@ -74,6 +82,10 @@
=>modifier=Modifier type=TypeLink name=Name '=' index=(LONG | HEX)
('[' (fieldOptions+=FieldOption (',' fieldOptions+=FieldOption)*)? ']')? (';')+;
+UnmodifiedMessageField returns MessageField:
+ type=TypeLink name=Name '=' index=(LONG | HEX)
+ ('[' (fieldOptions+=FieldOption (',' fieldOptions+=FieldOption)*)? ']')? (';')+;
+
enum Modifier:
required | optional | repeated;
@@ -219,7 +231,7 @@
ID | SafeReservedWord;
ReservedWord:
- SafeReservedWord | 'group';
+ SafeReservedWord | 'group' | 'oneof';
SafeReservedWord:
'package' | 'import' | 'public' | 'option' | 'extend' | 'message' | 'optional' | 'required' | 'repeated' |
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/ProtobufRuntimeModule.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/ProtobufRuntimeModule.java
index 68b658a..26c8496 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/ProtobufRuntimeModule.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/ProtobufRuntimeModule.java
@@ -12,6 +12,7 @@
import org.eclipse.xtext.conversion.IValueConverterService;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import org.eclipse.xtext.naming.IQualifiedNameProvider;
+import org.eclipse.xtext.parser.IAstFactory;
import org.eclipse.xtext.parser.antlr.ISyntaxErrorMessageProvider;
import org.eclipse.xtext.resource.IGlobalServiceProvider;
import org.eclipse.xtext.resource.XtextResource;
@@ -23,6 +24,7 @@
import com.google.eclipse.protobuf.linking.ProtobufResource;
import com.google.eclipse.protobuf.naming.ProtobufQualifiedNameConverter;
import com.google.eclipse.protobuf.naming.ProtobufQualifiedNameProvider;
+import com.google.eclipse.protobuf.parser.ProtobufAstFactory;
import com.google.eclipse.protobuf.resource.FastXtextResourceSet;
import com.google.eclipse.protobuf.resource.GlobalResourceServiceProvider;
import com.google.eclipse.protobuf.scoping.ExtensionRegistryProvider;
@@ -46,6 +48,10 @@
public Class<? extends IQualifiedNameConverter> bindIQualifiedNameConverter() {
return ProtobufQualifiedNameConverter.class;
}
+
+ @Override public Class<? extends IAstFactory> bindIAstFactory() {
+ return ProtobufAstFactory.class;
+ }
@Override public Class<? extends IQualifiedNameProvider> bindIQualifiedNameProvider() {
return ProtobufQualifiedNameProvider.class;
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/IndexedElements.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/IndexedElements.java
index d5554a3..6a8208f 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/IndexedElements.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/IndexedElements.java
@@ -21,6 +21,8 @@
import com.google.eclipse.protobuf.protobuf.FieldOption;
import com.google.eclipse.protobuf.protobuf.IndexedElement;
+import com.google.eclipse.protobuf.protobuf.MessageElement;
+import com.google.eclipse.protobuf.protobuf.OneOf;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -51,16 +53,24 @@
* @return the calculated value for the index of the given element.
*/
public long calculateNewIndexFor(IndexedElement e) {
- long index = 0;
EObject type = e.eContainer();
- for (EObject o : type.eContents()) {
- if (o == e || !(o instanceof IndexedElement)) {
- continue;
- }
- index = max(index, indexOf((IndexedElement) o));
- }
+ long index = findMaxIndex(type.eContents());
return ++index;
}
+
+ private long findMaxIndex(Iterable<? extends EObject> elements) {
+ long maxIndex = 0;
+
+ for (EObject e : elements) {
+ if (e instanceof OneOf) {
+ maxIndex = max(maxIndex, findMaxIndex(((OneOf) e).getElements()));
+ } else if (e instanceof IndexedElement) {
+ maxIndex = max(maxIndex, indexOf((IndexedElement) e));
+ }
+ }
+
+ return maxIndex;
+ }
/**
* Returns the name of the given <code>{@link IndexedElement}</code>.
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Messages.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Messages.java
index 0611784..cb48985 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Messages.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Messages.java
@@ -22,11 +22,14 @@
import com.google.eclipse.protobuf.protobuf.Message;
import com.google.eclipse.protobuf.protobuf.MessageElement;
import com.google.eclipse.protobuf.protobuf.MessageField;
+import com.google.eclipse.protobuf.protobuf.OneOf;
import com.google.eclipse.protobuf.protobuf.Protobuf;
import com.google.eclipse.protobuf.protobuf.TypeExtension;
import com.google.inject.Inject;
import com.google.inject.Singleton;
+import org.eclipse.emf.ecore.EObject;
+
/**
* Utility methods related to <code>{@link Message}</code>s.
*
@@ -64,11 +67,23 @@
*/
public Collection<MessageField> fieldsOf(Message message) {
List<MessageField> fields = newArrayList();
- for (MessageElement e : message.getElements()) {
- if (e instanceof MessageField) {
- fields.add((MessageField) e);
+ fieldsOf(message, fields);
+ return unmodifiableList(fields);
+ }
+
+ private void fieldsOf(EObject message, List<MessageField> fields) {
+ if (message instanceof Message) {
+ for (MessageElement e : ((Message) message).getElements()) {
+ if (e instanceof MessageField) {
+ fields.add((MessageField) e);
+ }
+ }
+ } else if (message instanceof OneOf) {
+ for (MessageElement e : ((OneOf) message).getElements()) {
+ if (e instanceof MessageField) {
+ fields.add((MessageField) e);
+ }
}
}
- return unmodifiableList(fields);
}
}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/parser/ProtobufAstFactory.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/parser/ProtobufAstFactory.java
new file mode 100644
index 0000000..dc8dc4f
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/parser/ProtobufAstFactory.java
@@ -0,0 +1,34 @@
+package com.google.eclipse.protobuf.parser;
+import com.google.eclipse.protobuf.protobuf.MessageField;
+import com.google.eclipse.protobuf.protobuf.Modifier;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.conversion.ValueConverterException;
+import org.eclipse.xtext.nodemodel.INode;
+import org.eclipse.xtext.parser.DefaultEcoreElementFactory;
+
+public class ProtobufAstFactory extends DefaultEcoreElementFactory {
+ private static final String UNMODIFIEDMESSAGEFIELD_RULE = "UnmodifiedMessageField";
+ private static final String ONEOFELEMENT_RULE = "OneOfElement";
+
+ @Override
+ public void add(EObject object, String feature, Object value, String ruleName, INode node)
+ throws ValueConverterException {
+ // TODO(foremans): Auto-generated method stub
+ super.add(object, feature, value, ruleName, node);
+ if (ONEOFELEMENT_RULE.equals(ruleName) && value instanceof MessageField) {
+ MessageField field = (MessageField) value;
+ field.setModifier(Modifier.OPTIONAL);
+ }
+ }
+
+ @Override
+ public void set(EObject object, String feature, Object value, String ruleName, INode node)
+ throws ValueConverterException {
+ super.set(object, feature, value, ruleName, node);
+ if (UNMODIFIEDMESSAGEFIELD_RULE.equals(ruleName)) {
+ MessageField field = (MessageField) object;
+ field.setModifier(Modifier.OPTIONAL);
+ }
+ }
+}
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 12cb9e1..82a7ed5 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
@@ -33,6 +33,7 @@
import com.google.eclipse.protobuf.protobuf.IndexedElement;
import com.google.eclipse.protobuf.protobuf.Message;
import com.google.eclipse.protobuf.protobuf.MessageElement;
+import com.google.eclipse.protobuf.protobuf.OneOf;
import com.google.eclipse.protobuf.protobuf.Package;
import com.google.eclipse.protobuf.protobuf.Protobuf;
import com.google.eclipse.protobuf.protobuf.ProtobufElement;
@@ -72,27 +73,39 @@
if (isNameNull(e)) {
return; // we already show an error if name is null, no need to go further.
}
- long index = indexedElements.indexOf(e);
+
EObject container = e.eContainer();
if (container instanceof Message) {
Message message = (Message) container;
- for (MessageElement element : message.getElements()) {
- if (!(element instanceof IndexedElement)) {
- continue;
+ Iterable<MessageElement> elements = message.getElements();
+ checkTagNumerIsUnique(e, message, elements);
+ }
+ }
+
+ private boolean checkTagNumerIsUnique(IndexedElement e, EObject message,
+ Iterable<MessageElement> elements) {
+ long index = indexedElements.indexOf(e);
+
+ for (MessageElement element : elements) {
+ if (element instanceof OneOf) {
+ if (!checkTagNumerIsUnique(e, message, ((OneOf) element).getElements())) {
+ return false;
}
+ } else if (element instanceof IndexedElement) {
IndexedElement other = (IndexedElement) element;
if (other == e) {
- break;
+ return true;
}
- if (indexedElements.indexOf(other) != index) {
- continue;
+ if (indexedElements.indexOf(other) == index) {
+ QualifiedName messageName = qualifiedNameProvider.getFullyQualifiedName(message);
+ String msg = format(fieldNumberAlreadyUsed, index, messageName.toString(), nameResolver.nameOf(other));
+ invalidTagNumberError(msg, e);
+ return false;
}
- QualifiedName messageName = qualifiedNameProvider.getFullyQualifiedName(message);
- String msg = format(fieldNumberAlreadyUsed, index, messageName.toString(), nameResolver.nameOf(other));
- invalidTagNumberError(msg, e);
- break;
}
}
+
+ return true;
}
@Check public void checkTagNumberIsGreaterThanZero(IndexedElement e) {