private Dictionary <IDescriptor, DescriptorDeclaration> CreateDeclarationMap() { var dictionary = new Dictionary <IDescriptor, DescriptorDeclaration>(); foreach (var location in Proto.SourceCodeInfo?.Location ?? Enumerable.Empty <Location>()) { var descriptor = FindDescriptorForPath(location.Path); if (descriptor != null) { dictionary[descriptor] = DescriptorDeclaration.FromProto(descriptor, location); } } return(dictionary); }
private Dictionary <IDescriptor, DescriptorDeclaration> CreateDeclarationMap() { var dictionary = new Dictionary <IDescriptor, DescriptorDeclaration>(); foreach (var location in Proto.SourceCodeInfo?.Location ?? Enumerable.Empty <Location>()) { var descriptor = FindDescriptorForPath(location.Path); if (descriptor != null) { dictionary[descriptor] = DescriptorDeclaration.FromProto(descriptor, location); } } return(dictionary); 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) { 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); } 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) { 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) { 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); } } }