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 { |