Working on supporting pluggable descriptor.proto definitions.
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/Descriptor_isOptimizeForOption_Test.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/Descriptor_isOptimizeForOption_Test.java deleted file mode 100644 index 034ed28..0000000 --- a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/Descriptor_isOptimizeForOption_Test.java +++ /dev/null
@@ -1,57 +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.junit.util.Finder.findOption; -import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertThat; - -import org.junit.*; - -import com.google.eclipse.protobuf.junit.core.XtextRule; -import com.google.eclipse.protobuf.protobuf.Option; -import com.google.eclipse.protobuf.protobuf.Protobuf; - -/** - * Tests for <code>{@link Descriptor#isOptimizeForOption(Option)}</code>. - * - * @author alruiz@google.com (Alex Ruiz) - */ -public class Descriptor_isOptimizeForOption_Test { - - @Rule public XtextRule xtext = new XtextRule(); - - private Descriptor descriptor; - - @Before public void setUp() { - descriptor = xtext.getInstanceOf(Descriptor.class); - } - - @Test public void should_return_true_if_option_is_OptimizeForOption() { - StringBuilder proto = new StringBuilder(); - proto.append("option java_generate_equals_and_hash = false;") - .append("option optimize_for = CODE_SIZE; "); - Protobuf root = xtext.parse(proto); - Option option = findOption("optimize_for", root); - assertThat(descriptor.isOptimizeForOption(option), equalTo(true)); - } - - @Test public void should_return_false_if_option_is_not_OptimizeForOption() { - StringBuilder proto = new StringBuilder(); - proto.append("option java_generate_equals_and_hash = false;") - .append("option optimize_for = CODE_SIZE; "); - Protobuf root = xtext.parse(proto); - Option option = findOption("java_generate_equals_and_hash", root); - assertThat(descriptor.isOptimizeForOption(option), equalTo(false)); - } - - @Test public void should_return_false_if_option_is_null() { - assertThat(descriptor.isOptimizeForOption(null), equalTo(false)); - } -}
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/Descriptor_lookupFileOption_Test.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/Descriptor_lookupFileOption_Test.java deleted file mode 100644 index 3637168..0000000 --- a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/Descriptor_lookupFileOption_Test.java +++ /dev/null
@@ -1,43 +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 org.hamcrest.core.IsEqual.equalTo; -import static org.hamcrest.core.IsNull.nullValue; -import static org.junit.Assert.assertThat; - -import org.junit.*; - -import com.google.eclipse.protobuf.junit.core.XtextRule; -import com.google.eclipse.protobuf.protobuf.Property; - -/** - * Tests for <code>{@link Descriptor#lookupFileOption(String)}</code>. - * - * @author alruiz@google.com (Alex Ruiz) - */ -public class Descriptor_lookupFileOption_Test { - - @Rule public XtextRule xtext = new XtextRule(); - - private Descriptor descriptor; - - @Before public void setUp() { - descriptor = xtext.getInstanceOf(Descriptor.class); - } - - @Test public void should_look_up_file_option() { - Property option = descriptor.lookupFileOption("java_multiple_files"); - assertThat(option.getName(), equalTo("java_multiple_files")); - } - - @Test public void should_return_null_if_option_not_found() { - assertThat(descriptor.lookupFileOption("hello"), nullValue()); - } -}
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/Descriptor_optimizedMode_Test.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/Descriptor_optimizedMode_Test.java deleted file mode 100644 index 60c0e17..0000000 --- a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/scoping/Descriptor_optimizedMode_Test.java +++ /dev/null
@@ -1,40 +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.junit.matchers.EnumHasLiterals.hasLiterals; -import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertThat; - -import org.junit.*; - -import com.google.eclipse.protobuf.junit.core.XtextRule; -import com.google.eclipse.protobuf.protobuf.Enum; - -/** - * Tests for <code>{@link Descriptor#optimizedMode()}</code>. - * - * @author alruiz@google.com (Alex Ruiz) - */ -public class Descriptor_optimizedMode_Test { - - @Rule public XtextRule xtext = new XtextRule(); - - private Descriptor descriptor; - - @Before public void setUp() { - descriptor = xtext.getInstanceOf(Descriptor.class); - } - - @Test public void should_return_enum_OptimizeMode() { - Enum optimizedMode = descriptor.optimizedMode(); - assertThat(optimizedMode.getName(), equalTo("OptimizeMode")); - assertThat(optimizedMode, hasLiterals("SPEED", "CODE_SIZE", "LITE_RUNTIME")); - } -}
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 5e85bcc..62e62a4 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
@@ -75,15 +75,25 @@ @Override public void completeOption_Name(EObject model, Assignment assignment, ContentAssistContext context, ICompletionProposalAcceptor acceptor) { + if (proposeOptions(model, context, acceptor)) return; if (model instanceof Option) { - proposeCommonFileOptions(context, acceptor); - return; - } - if (model instanceof Message) { - proposeCommonMessageOptions(context, acceptor); + EObject container = model.eContainer(); + proposeOptions(container, context, acceptor); } } + private boolean proposeOptions(EObject model, ContentAssistContext context, ICompletionProposalAcceptor acceptor) { + if (model instanceof Protobuf) { + proposeCommonFileOptions(context, acceptor); + return true; + } + if (model instanceof Message) { + proposeCommonMessageOptions(context, acceptor); + return true; + } + return false; + } + private void proposeCommonFileOptions(ContentAssistContext context, ICompletionProposalAcceptor acceptor) { for (Property fileOption : descriptorProvider.get().fileOptions()) { String displayString = fileOption.getName(); @@ -117,13 +127,13 @@ ICompletionProposalAcceptor acceptor) { Option option = (Option) model; Descriptor descriptor = descriptorProvider.get(); - Property fileOption = descriptor.lookupFileOption(option.getName()); - if (fileOption == null) fileOption = descriptor.lookupMessageOption(option.getName()); - if (fileOption == null) return; - if (descriptor.isOptimizeForOption(option)) { - proposeAndAccept(descriptor.optimizedMode(), context, acceptor); + Enum enumType = descriptor.enumTypeOf(option); + if (enumType != null) { + proposeAndAccept(enumType, context, acceptor); return; } + Property fileOption = descriptor.lookupOption(option.getName()); + if (fileOption == null) return; if (properties.isString(fileOption)) { proposeEmptyString(context, acceptor); return; @@ -215,7 +225,11 @@ EObject model = context.getCurrentModel(); if (model instanceof Property) return properties.isBool((Property) model); if (model instanceof Option) { - Property fileOption = descriptorProvider.get().lookupFileOption(((Option) model).getName()); + Property fileOption = descriptorProvider.get().lookupOption(((Option) model).getName()); + return fileOption != null && properties.isBool(fileOption); + } + if (model instanceof FieldOption) { + Property fileOption = descriptorProvider.get().lookupOption(((FieldOption) model).getName()); return fileOption != null && properties.isBool(fileOption); } return false; @@ -392,16 +406,17 @@ ICompletionProposalAcceptor acceptor) { FieldOption option = (FieldOption) model; Descriptor descriptor = descriptorProvider.get(); + Enum enumType = descriptor.enumTypeOf(option); + if (enumType != null) { + proposeAndAccept(enumType, context, acceptor); + return; + } Property fieldOption = descriptor.lookupFieldOption(option.getName()); if (fieldOption == null) return; if (properties.isBool(fieldOption)) { proposeBooleanValues(context, acceptor); return; } - if (descriptor.isCTypeOption(option)) { - proposeAndAccept(descriptor.cType(), context, acceptor); - return; - } } private void proposeBooleanValues(ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/ProtobufDocumentProvider.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/ProtobufDocumentProvider.java index a99d01b..fbf009e 100644 --- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/ProtobufDocumentProvider.java +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/ProtobufDocumentProvider.java
@@ -10,6 +10,7 @@ import static com.google.eclipse.protobuf.ui.ProtobufUiModule.PLUGIN_ID; import static com.google.eclipse.protobuf.ui.util.Resources.URI_SCHEME_FOR_FILES; +import static com.google.eclipse.protobuf.util.Closeables.close; import static java.util.Collections.singletonMap; import static org.eclipse.core.runtime.IStatus.ERROR; import static org.eclipse.emf.common.util.URI.createURI; @@ -43,7 +44,6 @@ private static final String ENCODING = "UTF-8"; - @Inject private Closeables closeables; @Inject private IResourceSetProvider resourceSetProvider; @Inject private Resources resources; @@ -120,7 +120,7 @@ } return contents.toString(); } finally { - if (!closeables.close(reader)) closeables.close(inputStream); + if (!close(reader)) close(inputStream); } }
diff --git a/com.google.eclipse.protobuf/descriptor.proto b/com.google.eclipse.protobuf/descriptor.proto new file mode 100644 index 0000000..4eeb43b --- /dev/null +++ b/com.google.eclipse.protobuf/descriptor.proto
@@ -0,0 +1,538 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// The messages in this file describe the definitions found in .proto files. +// A valid .proto file can be translated directly to a FileDescriptorProto +// without any other information (e.g. without reading its imports). + + + +package google.protobuf; +option java_package = "com.google.protobuf"; +option java_outer_classname = "DescriptorProtos"; + +// descriptor.proto must be optimized for speed because reflection-based +// algorithms don't work during bootstrapping. +option optimize_for = SPEED; + +// The protocol compiler can output a FileDescriptorSet containing the .proto +// files it parses. +message FileDescriptorSet { + repeated FileDescriptorProto file = 1; +} + +// Describes a complete .proto file. +message FileDescriptorProto { + optional string name = 1; // file name, relative to root of source tree + optional string package = 2; // e.g. "foo", "foo.bar", etc. + + // Names of files imported by this file. + repeated string dependency = 3; + + // All top-level definitions in this file. + repeated DescriptorProto message_type = 4; + repeated EnumDescriptorProto enum_type = 5; + repeated ServiceDescriptorProto service = 6; + repeated FieldDescriptorProto extension = 7; + + optional FileOptions options = 8; + + // This field contains optional information about the original source code. + // You may safely remove this entire field whithout harming runtime + // functionality of the descriptors -- the information is needed only by + // development tools. + optional SourceCodeInfo source_code_info = 9; +} + +// Describes a message type. +message DescriptorProto { + optional string name = 1; + + repeated FieldDescriptorProto field = 2; + repeated FieldDescriptorProto extension = 6; + + repeated DescriptorProto nested_type = 3; + repeated EnumDescriptorProto enum_type = 4; + + message ExtensionRange { + optional int32 start = 1; + optional int32 end = 2; + } + repeated ExtensionRange extension_range = 5; + + optional MessageOptions options = 7; +} + +// Describes a field within a message. +message FieldDescriptorProto { + enum Type { + // 0 is reserved for errors. + // Order is weird for historical reasons. + TYPE_DOUBLE = 1; + TYPE_FLOAT = 2; + TYPE_INT64 = 3; // Not ZigZag encoded. Negative numbers + // take 10 bytes. Use TYPE_SINT64 if negative + // values are likely. + TYPE_UINT64 = 4; + TYPE_INT32 = 5; // Not ZigZag encoded. Negative numbers + // take 10 bytes. Use TYPE_SINT32 if negative + // values are likely. + TYPE_FIXED64 = 6; + TYPE_FIXED32 = 7; + TYPE_BOOL = 8; + TYPE_STRING = 9; + TYPE_GROUP = 10; // Tag-delimited aggregate. + TYPE_MESSAGE = 11; // Length-delimited aggregate. + + // New in version 2. + TYPE_BYTES = 12; + TYPE_UINT32 = 13; + TYPE_ENUM = 14; + TYPE_SFIXED32 = 15; + TYPE_SFIXED64 = 16; + TYPE_SINT32 = 17; // Uses ZigZag encoding. + TYPE_SINT64 = 18; // Uses ZigZag encoding. + }; + + enum Label { + // 0 is reserved for errors + LABEL_OPTIONAL = 1; + LABEL_REQUIRED = 2; + LABEL_REPEATED = 3; + // TODO(sanjay): Should we add LABEL_MAP? + }; + + optional string name = 1; + optional int32 number = 3; + optional Label label = 4; + + // If type_name is set, this need not be set. If both this and type_name + // are set, this must be either TYPE_ENUM or TYPE_MESSAGE. + optional Type type = 5; + + // For message and enum types, this is the name of the type. If the name + // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping + // rules are used to find the type (i.e. first the nested types within this + // message are searched, then within the parent, on up to the root + // namespace). + optional string type_name = 6; + + // For extensions, this is the name of the type being extended. It is + // resolved in the same manner as type_name. + optional string extendee = 2; + + // For numeric types, contains the original text representation of the value. + // For booleans, "true" or "false". + // For strings, contains the default text contents (not escaped in any way). + // For bytes, contains the C escaped value. All bytes >= 128 are escaped. + // TODO(kenton): Base-64 encode? + optional string default_value = 7; + + optional FieldOptions options = 8; +} + +// Describes an enum type. +message EnumDescriptorProto { + optional string name = 1; + + repeated EnumValueDescriptorProto value = 2; + + optional EnumOptions options = 3; +} + +// Describes a value within an enum. +message EnumValueDescriptorProto { + optional string name = 1; + optional int32 number = 2; + + optional EnumValueOptions options = 3; +} + +// Describes a service. +message ServiceDescriptorProto { + optional string name = 1; + repeated MethodDescriptorProto method = 2; + + optional ServiceOptions options = 3; +} + +// Describes a method of a service. +message MethodDescriptorProto { + optional string name = 1; + + // Input and output type names. These are resolved in the same way as + // FieldDescriptorProto.type_name, but must refer to a message type. + optional string input_type = 2; + optional string output_type = 3; + + optional MethodOptions options = 4; +} + +// =================================================================== +// Options + +// Each of the definitions above may have "options" attached. These are +// just annotations which may cause code to be generated slightly differently +// or may contain hints for code that manipulates protocol messages. +// +// Clients may define custom options as extensions of the *Options messages. +// These extensions may not yet be known at parsing time, so the parser cannot +// store the values in them. Instead it stores them in a field in the *Options +// message called uninterpreted_option. This field must have the same name +// across all *Options messages. We then use this field to populate the +// extensions when we build a descriptor, at which point all protos have been +// parsed and so all extensions are known. +// +// Extension numbers for custom options may be chosen as follows: +// * For options which will only be used within a single application or +// organization, or for experimental options, use field numbers 50000 +// through 99999. It is up to you to ensure that you do not use the +// same number for multiple options. +// * For options which will be published and used publicly by multiple +// independent entities, e-mail protobuf-global-extension-registry@google.com +// to reserve extension numbers. Simply provide your project name (e.g. +// Object-C plugin) and your porject website (if available) -- there's no need +// to explain how you intend to use them. Usually you only need one extension +// number. You can declare multiple options with only one extension number by +// putting them in a sub-message. See the Custom Options section of the docs +// for examples: +// http://code.google.com/apis/protocolbuffers/docs/proto.html#options +// If this turns out to be popular, a web service will be set up +// to automatically assign option numbers. + + +message FileOptions { + + // Sets the Java package where classes generated from this .proto will be + // placed. By default, the proto package is used, but this is often + // inappropriate because proto packages do not normally start with backwards + // domain names. + optional string java_package = 1; + + + // If set, all the classes from the .proto file are wrapped in a single + // outer class with the given name. This applies to both Proto1 + // (equivalent to the old "--one_java_file" option) and Proto2 (where + // a .proto always translates to a single class, but you may want to + // explicitly choose the class name). + optional string java_outer_classname = 8; + + // If set true, then the Java code generator will generate a separate .java + // file for each top-level message, enum, and service defined in the .proto + // file. Thus, these types will *not* be nested inside the outer class + // named by java_outer_classname. However, the outer class will still be + // generated to contain the file's getDescriptor() method as well as any + // top-level extensions defined in the file. + optional bool java_multiple_files = 10 [default=false]; + + // If set true, then the Java code generator will generate equals() and + // hashCode() methods for all messages defined in the .proto file. This is + // purely a speed optimization, as the AbstractMessage base class includes + // reflection-based implementations of these methods. + optional bool java_generate_equals_and_hash = 20 [default=false]; + + // Generated classes can be optimized for speed or code size. + enum OptimizeMode { + SPEED = 1; // Generate complete code for parsing, serialization, + // etc. + CODE_SIZE = 2; // Use ReflectionOps to implement these methods. + LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. + } + optional OptimizeMode optimize_for = 9 [default=SPEED]; + + + + + // Should generic services be generated in each language? "Generic" services + // are not specific to any particular RPC system. They are generated by the + // main code generators in each language (without additional plugins). + // Generic services were the only kind of service generation supported by + // early versions of proto2. + // + // Generic services are now considered deprecated in favor of using plugins + // that generate code specific to your particular RPC system. Therefore, + // these default to false. Old code which depends on generic services should + // explicitly set them to true. + optional bool cc_generic_services = 16 [default=false]; + optional bool java_generic_services = 17 [default=false]; + optional bool py_generic_services = 18 [default=false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message MessageOptions { + // Set true to use the old proto1 MessageSet wire format for extensions. + // This is provided for backwards-compatibility with the MessageSet wire + // format. You should not use this for any other reason: It's less + // efficient, has fewer features, and is more complicated. + // + // The message must be defined exactly as follows: + // message Foo { + // option message_set_wire_format = true; + // extensions 4 to max; + // } + // Note that the message cannot have any defined fields; MessageSets only + // have extensions. + // + // All extensions of your type must be singular messages; e.g. they cannot + // be int32s, enums, or repeated messages. + // + // Because this is an option, the above two restrictions are not enforced by + // the protocol compiler. + optional bool message_set_wire_format = 1 [default=false]; + + // Disables the generation of the standard "descriptor()" accessor, which can + // conflict with a field of the same name. This is meant to make migration + // from proto1 easier; new code should avoid fields named "descriptor". + optional bool no_standard_descriptor_accessor = 2 [default=false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message FieldOptions { + // The ctype option instructs the C++ code generator to use a different + // representation of the field than it normally would. See the specific + // options below. This option is not yet implemented in the open source + // release -- sorry, we'll try to include it in a future version! + optional CType ctype = 1 [default = STRING]; + enum CType { + // Default mode. + STRING = 0; + + CORD = 1; + + STRING_PIECE = 2; + } + // The packed option can be enabled for repeated primitive fields to enable + // a more efficient representation on the wire. Rather than repeatedly + // writing the tag and type for each element, the entire array is encoded as + // a single length-delimited blob. + optional bool packed = 2; + + + // Is this field deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for accessors, or it will be completely ignored; in the very least, this + // is a formalization for deprecating fields. + optional bool deprecated = 3 [default=false]; + + // EXPERIMENTAL. DO NOT USE. + // For "map" fields, the name of the field in the enclosed type that + // is the key for this map. For example, suppose we have: + // message Item { + // required string name = 1; + // required string value = 2; + // } + // message Config { + // repeated Item items = 1 [experimental_map_key="name"]; + // } + // In this situation, the map key for Item will be set to "name". + // TODO: Fully-implement this, then remove the "experimental_" prefix. + optional string experimental_map_key = 9; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumOptions { + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumValueOptions { + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message ServiceOptions { + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message MethodOptions { + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +// A message representing a option the parser does not recognize. This only +// appears in options protos created by the compiler::Parser class. +// DescriptorPool resolves these when building Descriptor objects. Therefore, +// options protos in descriptor objects (e.g. returned by Descriptor::options(), +// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions +// in them. +message UninterpretedOption { + // The name of the uninterpreted option. Each string represents a segment in + // a dot-separated name. is_extension is true iff a segment represents an + // extension (denoted with parentheses in options specs in .proto files). + // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents + // "foo.(bar.baz).qux". + message NamePart { + required string name_part = 1; + required bool is_extension = 2; + } + repeated NamePart name = 2; + + // The value of the uninterpreted option, in whatever type the tokenizer + // identified it as during parsing. Exactly one of these should be set. + optional string identifier_value = 3; + optional uint64 positive_int_value = 4; + optional int64 negative_int_value = 5; + optional double double_value = 6; + optional bytes string_value = 7; + optional string aggregate_value = 8; +} + +// =================================================================== +// Optional source code info + +// Encapsulates information about the original source file from which a +// FileDescriptorProto was generated. +message SourceCodeInfo { + // A Location identifies a piece of source code in a .proto file which + // corresponds to a particular definition. This information is intended + // to be useful to IDEs, code indexers, documentation generators, and similar + // tools. + // + // For example, say we have a file like: + // message Foo { + // optional string foo = 1; + // } + // Let's look at just the field definition: + // optional string foo = 1; + // ^ ^^ ^^ ^ ^^^ + // a bc de f ghi + // We have the following locations: + // span path represents + // [a,i) [ 4, 0, 2, 0 ] The whole field definition. + // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). + // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). + // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). + // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). + // + // Notes: + // - A location may refer to a repeated field itself (i.e. not to any + // particular index within it). This is used whenever a set of elements are + // logically enclosed in a single code segment. For example, an entire + // extend block (possibly containing multiple extension definitions) will + // have an outer location whose path refers to the "extensions" repeated + // field without an index. + // - Multiple locations may have the same path. This happens when a single + // logical declaration is spread out across multiple places. The most + // obvious example is the "extend" block again -- there may be multiple + // extend blocks in the same scope, each of which will have the same path. + // - A location's span is not always a subset of its parent's span. For + // example, the "extendee" of an extension declaration appears at the + // beginning of the "extend" block and is shared by all extensions within + // the block. + // - Just because a location's span is a subset of some other location's span + // does not mean that it is a descendent. For example, a "group" defines + // both a type and a field in a single declaration. Thus, the locations + // corresponding to the type and field and their components will overlap. + // - Code which tries to interpret locations should probably be designed to + // ignore those that it doesn't understand, as more types of locations could + // be recorded in the future. + repeated Location location = 1; + message Location { + // Identifies which part of the FileDescriptorProto was defined at this + // location. + // + // Each element is a field number or an index. They form a path from + // the root FileDescriptorProto to the place where the definition. For + // example, this path: + // [ 4, 3, 2, 7, 1 ] + // refers to: + // file.message_type(3) // 4, 3 + // .field(7) // 2, 7 + // .name() // 1 + // This is because FileDescriptorProto.message_type has field number 4: + // repeated DescriptorProto message_type = 4; + // and DescriptorProto.field has field number 2: + // repeated FieldDescriptorProto field = 2; + // and FieldDescriptorProto.name has field number 1: + // optional string name = 1; + // + // Thus, the above path gives the location of a field name. If we removed + // the last element: + // [ 4, 3, 2, 7 ] + // this path refers to the whole field declaration (from the beginning + // of the label to the terminating semicolon). + repeated int32 path = 1 [packed=true]; + + // Always has exactly three or four elements: start line, start column, + // end line (optional, otherwise assumed same as start line), end column. + // These are packed into a single field for efficiency. Note that line + // and column numbers are zero-based -- typically you will want to add + // 1 to each before displaying to a user. + repeated int32 span = 2 [packed=true]; + + // TODO(kenton): Record comments appearing before and after the + // declaration. + } +}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/Descriptor.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/Descriptor.java index 50d770c..059ebb2 100644 --- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/Descriptor.java +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/Descriptor.java
@@ -9,23 +9,23 @@ package com.google.eclipse.protobuf.scoping; import static com.google.eclipse.protobuf.scoping.OptionType.*; +import static com.google.eclipse.protobuf.util.Closeables.close; import static java.util.Collections.unmodifiableCollection; import static org.eclipse.emf.common.util.URI.createURI; import static org.eclipse.xtext.EcoreUtil2.*; import static org.eclipse.xtext.util.CancelIndicator.NullImpl; -import java.io.*; -import java.util.*; - -import org.eclipse.xtext.parser.IParseResult; -import org.eclipse.xtext.parser.IParser; -import org.eclipse.xtext.resource.XtextResource; -import org.eclipse.xtext.util.StringInputStream; - import com.google.eclipse.protobuf.protobuf.*; import com.google.eclipse.protobuf.protobuf.Enum; import com.google.inject.Inject; +import org.eclipse.xtext.parser.*; +import org.eclipse.xtext.resource.XtextResource; + +import java.io.*; +import java.net.URL; +import java.util.*; + /** * Contains the elements from descriptor.proto (provided with protobuf's library.) * @@ -33,28 +33,29 @@ */ public class Descriptor { - private Protobuf root; + private static final String DESCRIPTOR_URI = "platform:/plugin/com.google.eclipse.protobuf/descriptor.proto"; private final Map<OptionType, Map<String, Property>> options = new HashMap<OptionType, Map<String, Property>>(); + private Protobuf root; private Enum optimizedMode; private Enum cType; - /** - * Creates a new </code>{@link Descriptor}</code>. - * @param parser the grammar parser. - */ @Inject public Descriptor(IParser parser) { addOptionTypes(); + InputStreamReader reader = null; try { - XtextResource resource = new XtextResource(createURI("descriptor.proto")); - IParseResult result = parser.parse(new InputStreamReader(globalScopeContents(), "UTF-8")); + XtextResource resource = new XtextResource(createURI(DESCRIPTOR_URI)); + reader = new InputStreamReader(globalScopeContents(), "UTF-8"); + IParseResult result = parser.parse(reader); root = (Protobuf) result.getRootASTElement(); resource.getContents().add(root); resolveLazyCrossReferences(resource, NullImpl); initContents(); } catch (IOException e) { - throw new IllegalStateException("Unable to parse global scope", e); + throw new IllegalStateException("Unable to parse descriptor.proto", e); + } finally { + close(reader); } } @@ -63,45 +64,9 @@ options.put(type, new LinkedHashMap<String, Property>()); } - private static InputStream globalScopeContents() { - return new StringInputStream(descriptorContents()); - } - - private static String descriptorContents() { - StringBuilder proto = new StringBuilder(); - proto.append("message FileOptions {") - .append(" optional string java_package = 1;") - .append(" optional string java_outer_classname = 8;") - .append(" optional bool java_multiple_files = 10 [default=false];") - .append(" optional bool java_generate_equals_and_hash = 20 [default=false];") - .append(" enum OptimizeMode {") - .append(" SPEED = 1;") - .append(" CODE_SIZE = 2;") - .append(" LITE_RUNTIME = 3;") - .append(" }") - .append(" optional OptimizeMode optimize_for = 9 [default=SPEED];") - .append(" optional bool cc_generic_services = 16 [default=false];") - .append(" optional bool java_generic_services = 17 [default=false];") - .append(" optional bool py_generic_services = 18 [default=false];") - .append(" extensions 1000 to max;") - .append("}") - .append("message MessageOptions {") - .append(" optional bool message_set_wire_format = 1 [default=false];") - .append(" optional bool no_standard_descriptor_accessor = 2 [default=false];") - .append(" extensions 1000 to max;") - .append("}") - .append("message FieldOptions {") - .append(" optional CType ctype = 1 [default = STRING];") - .append(" enum CType {") - .append(" STRING = 0;") - .append(" CORD = 1;") - .append(" STRING_PIECE = 2;") - .append(" }") - .append(" optional bool packed = 2;") - .append(" optional bool deprecated = 3 [default=false];") - .append(" extensions 1000 to max;") - .append("}"); - return proto.toString(); + private static InputStream globalScopeContents() throws IOException { + URL url = new URL(DESCRIPTOR_URI); + return url.openConnection().getInputStream(); } private void initContents() { @@ -192,35 +157,16 @@ } /** - * Returns the {@code enum} "OptimizeMode" (defined in {@code google/protobuf/descriptor.proto}. More details can be - * found <a href=http://code.google.com/apis/protocolbuffers/docs/proto.html#options" target="_blank">here</a>.) - * @return the {@code enum} "OptimizeMode." - */ - public Enum optimizedMode() { - return optimizedMode; - } - - /** - * Indicates whether the given option is the "optimize_for" one (defined in {@code google/protobuf/descriptor.proto}. - * More details can be found - * <a href=http://code.google.com/apis/protocolbuffers/docs/proto.html#options" target="_blank">here</a>.) - * @param option the given option. - * @return {@code true} if the given option is the "optimize_for" one, {@code false} otherwise. - */ - public boolean isOptimizeForOption(Option option) { - if (option == null) return false; - return "optimize_for".equals(option.getName()); - } - - /** - * Looks up a file-level option per name. File-level options are defined in {@code google/protobuf/descriptor.proto} + * Looks up an option per name, as defined in {@code google/protobuf/descriptor.proto} * (more details can be found <a * href=http://code.google.com/apis/protocolbuffers/docs/proto.html#options" target="_blank">here</a>.) * @param name the name of the option to look for. * @return the option whose name matches the given one or {@code null} if a matching option is not found. */ - public Property lookupFileOption(String name) { - return lookupOption(FILE, name); + public Property lookupOption(String name) { + Property p = lookupOption(FILE, name); + if (p == null) lookupOption(MESSAGE, name); + return p; } /** @@ -234,17 +180,6 @@ } /** - * Looks up a message-level option per name. Message-level options are defined in - * {@code google/protobuf/descriptor.proto} (more details can be found <a - * href=http://code.google.com/apis/protocolbuffers/docs/proto.html#options" target="_blank">here</a>.) - * @param name the name of the option to look for. - * @return the option whose name matches the given one or {@code null} if a matching option is not found. - */ - public Property lookupMessageOption(String name) { - return lookupOption(MESSAGE, name); - } - - /** * Returns all the field-level options available. These are the options defined in * {@code google/protobuf/descriptor.proto} (more details can be found * <a href=http://code.google.com/apis/protocolbuffers/docs/proto.html#options" target="_blank">here</a>.) @@ -274,23 +209,36 @@ } /** - * Indicates whether the given option is the "ctype" one (defined in {@code google/protobuf/descriptor.proto}. - * More details can be found - * <a href=http://code.google.com/apis/protocolbuffers/docs/proto.html#options" target="_blank">here</a>.) + * Returns the enum type of the given option, only if the given option is defined in + * {@code google/protobuf/descriptor.proto} and its type an enum (more details can be found <a + * href=http://code.google.com/apis/protocolbuffers/docs/proto.html#options" target="_blank">here</a>.) * @param option the given option. - * @return {@code true} if the given option is the "ctype" one, {@code false} otherwise. + * @return the enum type of the given option or {@code null} if the type of the given option is not enum. */ - public boolean isCTypeOption(FieldOption option) { + public Enum enumTypeOf(Option option) { + if (isOptimizeForOption(option)) return optimizedMode; + return null; + } + + private boolean isOptimizeForOption(Option option) { + if (option == null) return false; + return "optimize_for".equals(option.getName()); + } + + /** + * Returns the enum type of the given option, only if the given option is defined in + * {@code google/protobuf/descriptor.proto} and its type an enum (more details can be found <a + * href=http://code.google.com/apis/protocolbuffers/docs/proto.html#options" target="_blank">here</a>.) + * @param option the given option. + * @return the enum type of the given option or {@code null} if the type of the given option is not enum. + */ + public Enum enumTypeOf(FieldOption option) { + if (isCTypeOption(option)) return cType; + return null; + } + + private boolean isCTypeOption(FieldOption option) { if (option == null) return false; return "ctype".equals(option.getName()); } - - /** - * Returns the {@code enum} "CType" (defined in {@code google/protobuf/descriptor.proto}. More details can be - * found <a href=http://code.google.com/apis/protocolbuffers/docs/proto.html#options" target="_blank">here</a>.) - * @return the {@code enum} "CType." - */ - public Enum cType() { - return cType; - } }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/DescriptorProvider.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/DescriptorProvider.java index 2ff1323..dc481ea 100644 --- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/DescriptorProvider.java +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/DescriptorProvider.java
@@ -8,10 +8,10 @@ */ package com.google.eclipse.protobuf.scoping; -import org.eclipse.xtext.parser.IParser; - import com.google.inject.*; +import org.eclipse.xtext.parser.IParser; + /** * Provider of a singleton instance of <code>{@link Descriptor}</code>. *
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 0d09afb..963a962 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
@@ -122,7 +122,6 @@ try { return resourceSet.getResource(importUri, true); } catch (Throwable t) { - t.printStackTrace(); return null; } } @@ -161,15 +160,15 @@ Enum enumType = finder.enumTypeOf((Property) container); if (enumType != null) return scopeForLiterals(enumType); } + Enum enumType = enumTypeOfOption(container); + if (enumType != null) return scopeForLiterals(enumType); + return null; + } + + private Enum enumTypeOfOption(EObject mayBeOption) { Descriptor descriptor = descriptorProvider.get(); - if (container instanceof Option && descriptor.isOptimizeForOption((Option) container)) { - Enum optimizedMode = descriptor.optimizedMode(); - return scopeForLiterals(optimizedMode); - } - if (container instanceof FieldOption && descriptor.isCTypeOption((FieldOption) container)) { - Enum cType = descriptor.cType(); - return scopeForLiterals(cType); - } + if (mayBeOption instanceof Option) return descriptor.enumTypeOf((Option) mayBeOption); + if (mayBeOption instanceof FieldOption) return descriptor.enumTypeOf((FieldOption) mayBeOption); return null; }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Closeables.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/Closeables.java similarity index 74% rename from com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Closeables.java rename to com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/Closeables.java index 4abef77..7fdb025 100644 --- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Closeables.java +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/Closeables.java
@@ -3,26 +3,24 @@ * 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.ui.util; +package com.google.eclipse.protobuf.util; -import java.io.Closeable; -import java.io.IOException; - -import com.google.inject.Singleton; +import java.io.*; /** * Utility methods related to <code>{@link Closeable}</code>. * * @author alruiz@google.com (Alex Ruiz) */ -@Singleton public class Closeables { - - public boolean close(Closeable c) { + + public static boolean close(Closeable c) { if (c == null) return false; try { c.close(); } catch (IOException ignored) {} return true; } + + private Closeables() {} }