| Index: third_party/protobuf/java/src/main/java/com/google/protobuf/Descriptors.java
|
| ===================================================================
|
| --- third_party/protobuf/java/src/main/java/com/google/protobuf/Descriptors.java (revision 216642)
|
| +++ third_party/protobuf/java/src/main/java/com/google/protobuf/Descriptors.java (working copy)
|
| @@ -35,8 +35,10 @@
|
| import java.util.Arrays;
|
| import java.util.Collections;
|
| import java.util.HashMap;
|
| +import java.util.HashSet;
|
| import java.util.List;
|
| import java.util.Map;
|
| +import java.util.Set;
|
| import java.io.UnsupportedEncodingException;
|
|
|
| /**
|
| @@ -106,6 +108,11 @@
|
| return Collections.unmodifiableList(Arrays.asList(dependencies));
|
| }
|
|
|
| + /** Get a list of this file's public dependencies (public imports). */
|
| + public List<FileDescriptor> getPublicDependencies() {
|
| + return Collections.unmodifiableList(Arrays.asList(publicDependencies));
|
| + }
|
| +
|
| /**
|
| * Find a message type in the file by name. Does not find nested types.
|
| *
|
| @@ -216,7 +223,7 @@
|
| public static FileDescriptor buildFrom(final FileDescriptorProto proto,
|
| final FileDescriptor[] dependencies)
|
| throws DescriptorValidationException {
|
| - // Building decsriptors involves two steps: translating and linking.
|
| + // Building descriptors involves two steps: translating and linking.
|
| // In the translation step (implemented by FileDescriptor's
|
| // constructor), we build an object tree mirroring the
|
| // FileDescriptorProto's tree and put all of the descriptors into the
|
| @@ -317,12 +324,12 @@
|
| * {@link FileDescriptor#internalBuildGeneratedFileFrom}, the caller
|
| * provides a callback implementing this interface. The callback is called
|
| * after the FileDescriptor has been constructed, in order to assign all
|
| - * the global variales defined in the generated code which point at parts
|
| + * the global variables defined in the generated code which point at parts
|
| * of the FileDescriptor. The callback returns an ExtensionRegistry which
|
| * contains any extensions which might be used in the descriptor -- that
|
| * is, extensions of the various "Options" messages defined in
|
| * descriptor.proto. The callback may also return null to indicate that
|
| - * no extensions are used in the decsriptor.
|
| + * no extensions are used in the descriptor.
|
| */
|
| public interface InternalDescriptorAssigner {
|
| ExtensionRegistry assignDescriptors(FileDescriptor root);
|
| @@ -334,6 +341,7 @@
|
| private final ServiceDescriptor[] services;
|
| private final FieldDescriptor[] extensions;
|
| private final FileDescriptor[] dependencies;
|
| + private final FileDescriptor[] publicDependencies;
|
| private final DescriptorPool pool;
|
|
|
| private FileDescriptor(final FileDescriptorProto proto,
|
| @@ -343,6 +351,17 @@
|
| this.pool = pool;
|
| this.proto = proto;
|
| this.dependencies = dependencies.clone();
|
| + this.publicDependencies =
|
| + new FileDescriptor[proto.getPublicDependencyCount()];
|
| + for (int i = 0; i < proto.getPublicDependencyCount(); i++) {
|
| + int index = proto.getPublicDependency(i);
|
| + if (index < 0 || index >= this.dependencies.length) {
|
| + throw new DescriptorValidationException(this,
|
| + "Invalid public dependency index.");
|
| + }
|
| + this.publicDependencies[i] =
|
| + this.dependencies[proto.getPublicDependency(i)];
|
| + }
|
|
|
| pool.addPackage(getPackage(), this);
|
|
|
| @@ -390,7 +409,7 @@
|
| * in the original. This method is needed for bootstrapping when a file
|
| * defines custom options. The options may be defined in the file itself,
|
| * so we can't actually parse them until we've constructed the descriptors,
|
| - * but to construct the decsriptors we have to have parsed the descriptor
|
| + * but to construct the descriptors we have to have parsed the descriptor
|
| * protos. So, we have to parse the descriptor protos a second time after
|
| * constructing the descriptors.
|
| */
|
| @@ -641,7 +660,7 @@
|
| FieldSet.FieldDescriptorLite<FieldDescriptor> {
|
| /**
|
| * Get the index of this descriptor within its parent.
|
| - * @see Descriptor#getIndex()
|
| + * @see Descriptors.Descriptor#getIndex()
|
| */
|
| public int getIndex() { return index; }
|
|
|
| @@ -656,7 +675,7 @@
|
|
|
| /**
|
| * Get the field's fully-qualified name.
|
| - * @see Descriptor#getFullName()
|
| + * @see Descriptors.Descriptor#getFullName()
|
| */
|
| public String getFullName() { return fullName; }
|
|
|
| @@ -943,7 +962,8 @@
|
| private void crossLink() throws DescriptorValidationException {
|
| if (proto.hasExtendee()) {
|
| final GenericDescriptor extendee =
|
| - file.pool.lookupSymbol(proto.getExtendee(), this);
|
| + file.pool.lookupSymbol(proto.getExtendee(), this,
|
| + DescriptorPool.SearchFilter.TYPES_ONLY);
|
| if (!(extendee instanceof Descriptor)) {
|
| throw new DescriptorValidationException(this,
|
| '\"' + proto.getExtendee() + "\" is not a message type.");
|
| @@ -960,7 +980,8 @@
|
|
|
| if (proto.hasTypeName()) {
|
| final GenericDescriptor typeDescriptor =
|
| - file.pool.lookupSymbol(proto.getTypeName(), this);
|
| + file.pool.lookupSymbol(proto.getTypeName(), this,
|
| + DescriptorPool.SearchFilter.TYPES_ONLY);
|
|
|
| if (!proto.hasType()) {
|
| // Choose field type based on symbol.
|
| @@ -1149,7 +1170,7 @@
|
| implements GenericDescriptor, Internal.EnumLiteMap<EnumValueDescriptor> {
|
| /**
|
| * Get the index of this descriptor within its parent.
|
| - * @see Descriptor#getIndex()
|
| + * @see Descriptors.Descriptor#getIndex()
|
| */
|
| public int getIndex() { return index; }
|
|
|
| @@ -1161,7 +1182,7 @@
|
|
|
| /**
|
| * Get the type's fully-qualified name.
|
| - * @see Descriptor#getFullName()
|
| + * @see Descriptors.Descriptor#getFullName()
|
| */
|
| public String getFullName() { return fullName; }
|
|
|
| @@ -1182,7 +1203,7 @@
|
| /**
|
| * Find an enum value by name.
|
| * @param name The unqualified name of the value (e.g. "FOO").
|
| - * @return the value's decsriptor, or {@code null} if not found.
|
| + * @return the value's descriptor, or {@code null} if not found.
|
| */
|
| public EnumValueDescriptor findValueByName(final String name) {
|
| final GenericDescriptor result =
|
| @@ -1198,7 +1219,7 @@
|
| * Find an enum value by number. If multiple enum values have the same
|
| * number, this returns the first defined value with that number.
|
| * @param number The value's number.
|
| - * @return the value's decsriptor, or {@code null} if not found.
|
| + * @return the value's descriptor, or {@code null} if not found.
|
| */
|
| public EnumValueDescriptor findValueByNumber(final int number) {
|
| return file.pool.enumValuesByNumber.get(
|
| @@ -1261,7 +1282,7 @@
|
| implements GenericDescriptor, Internal.EnumLite {
|
| /**
|
| * Get the index of this descriptor within its parent.
|
| - * @see Descriptor#getIndex()
|
| + * @see Descriptors.Descriptor#getIndex()
|
| */
|
| public int getIndex() { return index; }
|
|
|
| @@ -1276,7 +1297,7 @@
|
|
|
| /**
|
| * Get the value's fully-qualified name.
|
| - * @see Descriptor#getFullName()
|
| + * @see Descriptors.Descriptor#getFullName()
|
| */
|
| public String getFullName() { return fullName; }
|
|
|
| @@ -1337,7 +1358,7 @@
|
|
|
| /**
|
| * Get the type's fully-qualified name.
|
| - * @see Descriptor#getFullName()
|
| + * @see Descriptors.Descriptor#getFullName()
|
| */
|
| public String getFullName() { return fullName; }
|
|
|
| @@ -1355,7 +1376,7 @@
|
| /**
|
| * Find a method by name.
|
| * @param name The unqualified name of the method (e.g. "Foo").
|
| - * @return the method's decsriptor, or {@code null} if not found.
|
| + * @return the method's descriptor, or {@code null} if not found.
|
| */
|
| public MethodDescriptor findMethodByName(final String name) {
|
| final GenericDescriptor result =
|
| @@ -1427,7 +1448,7 @@
|
|
|
| /**
|
| * Get the method's fully-qualified name.
|
| - * @see Descriptor#getFullName()
|
| + * @see Descriptors.Descriptor#getFullName()
|
| */
|
| public String getFullName() { return fullName; }
|
|
|
| @@ -1475,7 +1496,8 @@
|
|
|
| private void crossLink() throws DescriptorValidationException {
|
| final GenericDescriptor input =
|
| - file.pool.lookupSymbol(proto.getInputType(), this);
|
| + file.pool.lookupSymbol(proto.getInputType(), this,
|
| + DescriptorPool.SearchFilter.TYPES_ONLY);
|
| if (!(input instanceof Descriptor)) {
|
| throw new DescriptorValidationException(this,
|
| '\"' + proto.getInputType() + "\" is not a message type.");
|
| @@ -1483,7 +1505,8 @@
|
| inputType = (Descriptor)input;
|
|
|
| final GenericDescriptor output =
|
| - file.pool.lookupSymbol(proto.getOutputType(), this);
|
| + file.pool.lookupSymbol(proto.getOutputType(), this,
|
| + DescriptorPool.SearchFilter.TYPES_ONLY);
|
| if (!(output instanceof Descriptor)) {
|
| throw new DescriptorValidationException(this,
|
| '\"' + proto.getOutputType() + "\" is not a message type.");
|
| @@ -1535,7 +1558,7 @@
|
| public String getProblemSymbolName() { return name; }
|
|
|
| /**
|
| - * Gets the the protocol message representation of the invalid descriptor.
|
| + * Gets the protocol message representation of the invalid descriptor.
|
| */
|
| public Message getProblemProto() { return proto; }
|
|
|
| @@ -1590,14 +1613,22 @@
|
| * descriptors defined in a particular file.
|
| */
|
| private static final class DescriptorPool {
|
| +
|
| + /** Defines what subclass of descriptors to search in the descriptor pool.
|
| + */
|
| + enum SearchFilter {
|
| + TYPES_ONLY, AGGREGATES_ONLY, ALL_SYMBOLS
|
| + }
|
| +
|
| DescriptorPool(final FileDescriptor[] dependencies) {
|
| - this.dependencies = new DescriptorPool[dependencies.length];
|
| + this.dependencies = new HashSet<FileDescriptor>();
|
|
|
| - for (int i = 0; i < dependencies.length; i++) {
|
| - this.dependencies[i] = dependencies[i].pool;
|
| + for (int i = 0; i < dependencies.length; i++) {
|
| + this.dependencies.add(dependencies[i]);
|
| + importPublicDependencies(dependencies[i]);
|
| }
|
|
|
| - for (final FileDescriptor dependency : dependencies) {
|
| + for (final FileDescriptor dependency : this.dependencies) {
|
| try {
|
| addPackage(dependency.getPackage(), dependency);
|
| } catch (DescriptorValidationException e) {
|
| @@ -1609,8 +1640,17 @@
|
| }
|
| }
|
|
|
| - private final DescriptorPool[] dependencies;
|
| + /** Find and put public dependencies of the file into dependencies set.*/
|
| + private void importPublicDependencies(final FileDescriptor file) {
|
| + for (FileDescriptor dependency : file.getPublicDependencies()) {
|
| + if (dependencies.add(dependency)) {
|
| + importPublicDependencies(dependency);
|
| + }
|
| + }
|
| + }
|
|
|
| + private final Set<FileDescriptor> dependencies;
|
| +
|
| private final Map<String, GenericDescriptor> descriptorsByName =
|
| new HashMap<String, GenericDescriptor>();
|
| private final Map<DescriptorIntPair, FieldDescriptor> fieldsByNumber =
|
| @@ -1620,39 +1660,81 @@
|
|
|
| /** Find a generic descriptor by fully-qualified name. */
|
| GenericDescriptor findSymbol(final String fullName) {
|
| + return findSymbol(fullName, SearchFilter.ALL_SYMBOLS);
|
| + }
|
| +
|
| + /** Find a descriptor by fully-qualified name and given option to only
|
| + * search valid field type descriptors.
|
| + */
|
| + GenericDescriptor findSymbol(final String fullName,
|
| + final SearchFilter filter) {
|
| GenericDescriptor result = descriptorsByName.get(fullName);
|
| if (result != null) {
|
| - return result;
|
| + if ((filter==SearchFilter.ALL_SYMBOLS) ||
|
| + ((filter==SearchFilter.TYPES_ONLY) && isType(result)) ||
|
| + ((filter==SearchFilter.AGGREGATES_ONLY) && isAggregate(result))) {
|
| + return result;
|
| + }
|
| }
|
|
|
| - for (final DescriptorPool dependency : dependencies) {
|
| - result = dependency.descriptorsByName.get(fullName);
|
| + for (final FileDescriptor dependency : dependencies) {
|
| + result = dependency.pool.descriptorsByName.get(fullName);
|
| if (result != null) {
|
| - return result;
|
| + if ((filter==SearchFilter.ALL_SYMBOLS) ||
|
| + ((filter==SearchFilter.TYPES_ONLY) && isType(result)) ||
|
| + ((filter==SearchFilter.AGGREGATES_ONLY) && isAggregate(result))) {
|
| + return result;
|
| + }
|
| }
|
| }
|
|
|
| return null;
|
| }
|
|
|
| + /** Checks if the descriptor is a valid type for a message field. */
|
| + boolean isType(GenericDescriptor descriptor) {
|
| + return (descriptor instanceof Descriptor) ||
|
| + (descriptor instanceof EnumDescriptor);
|
| + }
|
| +
|
| + /** Checks if the descriptor is a valid namespace type. */
|
| + boolean isAggregate(GenericDescriptor descriptor) {
|
| + return (descriptor instanceof Descriptor) ||
|
| + (descriptor instanceof EnumDescriptor) ||
|
| + (descriptor instanceof PackageDescriptor) ||
|
| + (descriptor instanceof ServiceDescriptor);
|
| + }
|
| +
|
| /**
|
| - * Look up a descriptor by name, relative to some other descriptor.
|
| + * Look up a type descriptor by name, relative to some other descriptor.
|
| * The name may be fully-qualified (with a leading '.'),
|
| * partially-qualified, or unqualified. C++-like name lookup semantics
|
| * are used to search for the matching descriptor.
|
| */
|
| GenericDescriptor lookupSymbol(final String name,
|
| - final GenericDescriptor relativeTo)
|
| + final GenericDescriptor relativeTo,
|
| + final DescriptorPool.SearchFilter filter)
|
| throws DescriptorValidationException {
|
| // TODO(kenton): This could be optimized in a number of ways.
|
|
|
| GenericDescriptor result;
|
| if (name.startsWith(".")) {
|
| // Fully-qualified name.
|
| - result = findSymbol(name.substring(1));
|
| + result = findSymbol(name.substring(1), filter);
|
| } else {
|
| // If "name" is a compound identifier, we want to search for the
|
| // first component of it, then search within it for the rest.
|
| + // If name is something like "Foo.Bar.baz", and symbols named "Foo" are
|
| + // defined in multiple parent scopes, we only want to find "Bar.baz" in
|
| + // the innermost one. E.g., the following should produce an error:
|
| + // message Bar { message Baz {} }
|
| + // message Foo {
|
| + // message Bar {
|
| + // }
|
| + // optional Bar.Baz baz = 1;
|
| + // }
|
| + // So, we look for just "Foo" first, then look for "Bar.baz" within it
|
| + // if found.
|
| final int firstPartLength = name.indexOf('.');
|
| final String firstPart;
|
| if (firstPartLength == -1) {
|
| @@ -1670,14 +1752,15 @@
|
| // Chop off the last component of the scope.
|
| final int dotpos = scopeToTry.lastIndexOf(".");
|
| if (dotpos == -1) {
|
| - result = findSymbol(name);
|
| + result = findSymbol(name, filter);
|
| break;
|
| } else {
|
| scopeToTry.setLength(dotpos + 1);
|
|
|
| - // Append firstPart and try to find.
|
| + // Append firstPart and try to find
|
| scopeToTry.append(firstPart);
|
| - result = findSymbol(scopeToTry.toString());
|
| + result = findSymbol(scopeToTry.toString(),
|
| + DescriptorPool.SearchFilter.AGGREGATES_ONLY);
|
|
|
| if (result != null) {
|
| if (firstPartLength != -1) {
|
| @@ -1686,7 +1769,7 @@
|
| // searching parent scopes.
|
| scopeToTry.setLength(dotpos + 1);
|
| scopeToTry.append(name);
|
| - result = findSymbol(scopeToTry.toString());
|
| + result = findSymbol(scopeToTry.toString(), filter);
|
| }
|
| break;
|
| }
|
| @@ -1817,7 +1900,7 @@
|
|
|
| /**
|
| * Adds a field to the fieldsByNumber table. Throws an exception if a
|
| - * field with hte same containing type and number already exists.
|
| + * field with the same containing type and number already exists.
|
| */
|
| void addFieldByNumber(final FieldDescriptor field)
|
| throws DescriptorValidationException {
|
|
|