|  | @@ -98,64 +98,65 @@ namespace Google.Protobuf.Reflection
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              return dictionary;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            IDescriptor FindDescriptorForPath(IList<int> path)
 | 
	
		
			
				|  |  | +        private IDescriptor FindDescriptorForPath(IList<int> path)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            // All complete declarations have an even, non-empty path length
 | 
	
		
			
				|  |  | +            // (There can be an empty path for a descriptor declaration, but that can't have any comments,
 | 
	
		
			
				|  |  | +            // so we currently ignore it.)
 | 
	
		
			
				|  |  | +            if (path.Count == 0 || (path.Count & 1) != 0)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                // All complete declarations have an even, non-empty path length
 | 
	
		
			
				|  |  | -                // (There can be an empty path for a descriptor declaration, but that can't have any comments,
 | 
	
		
			
				|  |  | -                // so we currently ignore it.)
 | 
	
		
			
				|  |  | -                if (path.Count == 0 || (path.Count & 1) != 0)
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    return null;
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -                IReadOnlyList<DescriptorBase> topLevelList = GetNestedDescriptorListForField(path[0]);
 | 
	
		
			
				|  |  | -                DescriptorBase current = GetDescriptorFromList(topLevelList, path[1]);
 | 
	
		
			
				|  |  | +                return null;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            IReadOnlyList<DescriptorBase> topLevelList = GetNestedDescriptorListForField(path[0]);
 | 
	
		
			
				|  |  | +            DescriptorBase current = GetDescriptorFromList(topLevelList, path[1]);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                for (int i = 2; current != null && i < path.Count; i += 2)
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    var list = current.GetNestedDescriptorListForField(path[i]);
 | 
	
		
			
				|  |  | -                    current = GetDescriptorFromList(list, path[i + 1]);
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -                return current;
 | 
	
		
			
				|  |  | +            for (int i = 2; current != null && i < path.Count; i += 2)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                var list = current.GetNestedDescriptorListForField(path[i]);
 | 
	
		
			
				|  |  | +                current = GetDescriptorFromList(list, path[i + 1]);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | +            return current;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            DescriptorBase GetDescriptorFromList(IReadOnlyList<DescriptorBase> list, int index)
 | 
	
		
			
				|  |  | +        private DescriptorBase GetDescriptorFromList(IReadOnlyList<DescriptorBase> list, int index)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            // This is fine: it may be a newer version of protobuf than we understand, with a new descriptor
 | 
	
		
			
				|  |  | +            // field.
 | 
	
		
			
				|  |  | +            if (list == null)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                // This is fine: it may be a newer version of protobuf than we understand, with a new descriptor
 | 
	
		
			
				|  |  | -                // field.
 | 
	
		
			
				|  |  | -                if (list == null)
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    return null;
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -                // We *could* return null to silently continue, but this is basically data corruption.
 | 
	
		
			
				|  |  | -                if (index < 0 || index >= list.Count)
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    // We don't have much extra information to give at this point unfortunately. If this becomes a problem,
 | 
	
		
			
				|  |  | -                    // we can pass in the complete path and report that and the file name.
 | 
	
		
			
				|  |  | -                    throw new InvalidProtocolBufferException($"Invalid descriptor location path: index out of range");
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -                return list[index];
 | 
	
		
			
				|  |  | +                return null;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            // We *could* return null to silently continue, but this is basically data corruption.
 | 
	
		
			
				|  |  | +            if (index < 0 || index >= list.Count)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                // We don't have much extra information to give at this point unfortunately. If this becomes a problem,
 | 
	
		
			
				|  |  | +                // we can pass in the complete path and report that and the file name.
 | 
	
		
			
				|  |  | +                throw new InvalidProtocolBufferException($"Invalid descriptor location path: index out of range");
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | +            return list[index];
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            IReadOnlyList<DescriptorBase> GetNestedDescriptorListForField(int fieldNumber)
 | 
	
		
			
				|  |  | +        private IReadOnlyList<DescriptorBase> GetNestedDescriptorListForField(int fieldNumber)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            switch (fieldNumber)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                switch (fieldNumber)
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    case FileDescriptorProto.ServiceFieldNumber:
 | 
	
		
			
				|  |  | -                        return (IReadOnlyList<DescriptorBase>) Services;
 | 
	
		
			
				|  |  | -                    case FileDescriptorProto.MessageTypeFieldNumber:
 | 
	
		
			
				|  |  | -                        return (IReadOnlyList<DescriptorBase>) MessageTypes;
 | 
	
		
			
				|  |  | -                    case FileDescriptorProto.EnumTypeFieldNumber:
 | 
	
		
			
				|  |  | -                        return (IReadOnlyList<DescriptorBase>) EnumTypes;
 | 
	
		
			
				|  |  | -                    default:
 | 
	
		
			
				|  |  | -                        return null;
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | +                case FileDescriptorProto.ServiceFieldNumber:
 | 
	
		
			
				|  |  | +                    return (IReadOnlyList<DescriptorBase>) Services;
 | 
	
		
			
				|  |  | +                case FileDescriptorProto.MessageTypeFieldNumber:
 | 
	
		
			
				|  |  | +                    return (IReadOnlyList<DescriptorBase>) MessageTypes;
 | 
	
		
			
				|  |  | +                case FileDescriptorProto.EnumTypeFieldNumber:
 | 
	
		
			
				|  |  | +                    return (IReadOnlyList<DescriptorBase>) EnumTypes;
 | 
	
		
			
				|  |  | +                default:
 | 
	
		
			
				|  |  | +                    return null;
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          internal DescriptorDeclaration GetDeclaration(IDescriptor descriptor)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            declarations.Value.TryGetValue(descriptor, out var declaration);
 | 
	
		
			
				|  |  | +            DescriptorDeclaration declaration;
 | 
	
		
			
				|  |  | +            declarations.Value.TryGetValue(descriptor, out declaration);
 | 
	
		
			
				|  |  |              return declaration;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -191,7 +192,8 @@ namespace Google.Protobuf.Reflection
 | 
	
		
			
				|  |  |                      throw new DescriptorValidationException(@this, "Invalid public dependency index.");
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |                  string name = proto.Dependency[index];
 | 
	
		
			
				|  |  | -                if (!nameToFileMap.TryGetValue(name, out var file))
 | 
	
		
			
				|  |  | +                FileDescriptor file;
 | 
	
		
			
				|  |  | +                if (!nameToFileMap.TryGetValue(name, out file))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  |                      if (!allowUnknownDependencies)
 | 
	
		
			
				|  |  |                      {
 | 
	
	
		
			
				|  | @@ -414,7 +416,8 @@ namespace Google.Protobuf.Reflection
 | 
	
		
			
				|  |  |                  var dependencies = new List<FileDescriptor>();
 | 
	
		
			
				|  |  |                  foreach (var dependencyName in proto.Dependency)
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    if (!descriptorsByName.TryGetValue(dependencyName, out var dependency))
 | 
	
		
			
				|  |  | +                    FileDescriptor dependency;
 | 
	
		
			
				|  |  | +                    if (!descriptorsByName.TryGetValue(dependencyName, out dependency))
 | 
	
		
			
				|  |  |                      {
 | 
	
		
			
				|  |  |                          throw new ArgumentException($"Dependency missing: {dependencyName}");
 | 
	
		
			
				|  |  |                      }
 |