Bump corefx
[mono.git] / mcs / class / referencesource / mscorlib / system / throwhelper.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6
7 namespace System {
8     // This file defines an internal class used to throw exceptions in BCL code.
9     // The main purpose is to reduce code size. 
10     // 
11     // The old way to throw an exception generates quite a lot IL code and assembly code.
12     // Following is an example:
13     //     C# source
14     //          throw new ArgumentNullException("key", Environment.GetResourceString("ArgumentNull_Key"));
15     //     IL code:
16     //          IL_0003:  ldstr      "key"
17     //          IL_0008:  ldstr      "ArgumentNull_Key"
18     //          IL_000d:  call       string System.Environment::GetResourceString(string)
19     //          IL_0012:  newobj     instance void System.ArgumentNullException::.ctor(string,string)
20     //          IL_0017:  throw
21     //    which is 21bytes in IL.
22     // 
23     // So we want to get rid of the ldstr and call to Environment.GetResource in IL.
24     // In order to do that, I created two enums: ExceptionResource, ExceptionArgument to represent the
25     // argument name and resource name in a small integer. The source code will be changed to 
26     //    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key, ExceptionResource.ArgumentNull_Key);
27     //
28     // The IL code will be 7 bytes.
29     //    IL_0008:  ldc.i4.4
30     //    IL_0009:  ldc.i4.4
31     //    IL_000a:  call       void System.ThrowHelper::ThrowArgumentNullException(valuetype System.ExceptionArgument)
32     //    IL_000f:  ldarg.0
33     //
34     // This will also reduce the Jitted code size a lot. 
35     //
36     // It is very important we do this for generic classes because we can easily generate the same code 
37     // multiple times for different instantiation. 
38     // 
39     // <
40
41
42
43
44
45
46
47
48
49     using System.Runtime.CompilerServices;        
50     using System.Runtime.Serialization;
51     using System.Diagnostics.Contracts;
52
53     [Pure]
54     internal static partial class ThrowHelper {
55         internal static void ThrowArgumentOutOfRangeException() {        
56             ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_Index);            
57         }
58
59         internal static void ThrowWrongKeyTypeArgumentException(object key, Type targetType) {
60             throw new ArgumentException(Environment.GetResourceString("Arg_WrongType", key, targetType), "key");
61         }
62
63         internal static void ThrowWrongValueTypeArgumentException(object value, Type targetType) {
64             throw new ArgumentException(Environment.GetResourceString("Arg_WrongType", value, targetType), "value");
65         }
66
67         internal static void ThrowKeyNotFoundException() {
68             throw new System.Collections.Generic.KeyNotFoundException();
69         }
70         
71         internal static void ThrowArgumentException(ExceptionResource resource) {
72             throw new ArgumentException(Environment.GetResourceString(GetResourceName(resource)));
73         }
74
75         internal static void ThrowArgumentException(ExceptionResource resource, ExceptionArgument argument) {
76             throw new ArgumentException(Environment.GetResourceString(GetResourceName(resource)), GetArgumentName(argument));
77         }
78
79 #if !MONO
80         internal static void ThrowArgumentNullException(ExceptionArgument argument) {
81             throw new ArgumentNullException(GetArgumentName(argument));
82         }
83
84         internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument) {
85             throw new ArgumentOutOfRangeException(GetArgumentName(argument));
86         }
87 #endif
88
89         internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource) {
90                 
91             if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
92                 // Dev11 474369 quirk: Mango had an empty message string:
93                 throw new ArgumentOutOfRangeException(GetArgumentName(argument), String.Empty);                                                  
94             } else {
95                 throw new ArgumentOutOfRangeException(GetArgumentName(argument),
96                                                       Environment.GetResourceString(GetResourceName(resource)));
97             }            
98         }
99
100         internal static void ThrowInvalidOperationException(ExceptionResource resource) {
101             throw new InvalidOperationException(Environment.GetResourceString(GetResourceName(resource)));
102         }
103
104         internal static void ThrowSerializationException(ExceptionResource resource) {
105             throw new SerializationException(Environment.GetResourceString(GetResourceName(resource)));
106         }
107
108         internal static void  ThrowSecurityException(ExceptionResource resource) {
109             throw new System.Security.SecurityException(Environment.GetResourceString(GetResourceName(resource)));            
110         }
111
112         internal static void ThrowNotSupportedException(ExceptionResource resource) {
113             throw new NotSupportedException(Environment.GetResourceString(GetResourceName(resource)));
114         }
115
116         internal static void ThrowUnauthorizedAccessException(ExceptionResource resource) {
117             throw new UnauthorizedAccessException(Environment.GetResourceString(GetResourceName(resource)));
118         }
119
120         internal static void ThrowObjectDisposedException(string objectName, ExceptionResource resource) {
121             throw new ObjectDisposedException(objectName, Environment.GetResourceString(GetResourceName(resource)));
122         }
123
124         // Allow nulls for reference types and Nullable<U>, but not for value types.
125         internal static void IfNullAndNullsAreIllegalThenThrow<T>(object value, ExceptionArgument argName) {
126             // Note that default(T) is not equal to null for value types except when T is Nullable<U>. 
127             if (value == null && !(default(T) == null))
128                 ThrowHelper.ThrowArgumentNullException(argName);
129         }
130
131         //
132         // This function will convert an ExceptionArgument enum value to the argument name string.
133         //
134         internal static string GetArgumentName(ExceptionArgument argument) {
135             string argumentName = null;
136
137             switch (argument) {
138                 case ExceptionArgument.array:
139                     argumentName = "array";
140                     break;
141
142                 case ExceptionArgument.arrayIndex:
143                     argumentName = "arrayIndex";
144                     break;
145
146                 case ExceptionArgument.capacity:
147                     argumentName = "capacity";
148                     break;
149
150                 case ExceptionArgument.collection:
151                     argumentName = "collection";
152                     break;
153
154                 case ExceptionArgument.list:
155                     argumentName = "list";
156                     break;
157
158                 case ExceptionArgument.converter:
159                     argumentName = "converter";
160                     break;
161
162                 case ExceptionArgument.count:
163                     argumentName = "count";
164                     break;
165
166                 case ExceptionArgument.dictionary:
167                     argumentName = "dictionary";
168                     break;
169
170                 case ExceptionArgument.dictionaryCreationThreshold:
171                     argumentName = "dictionaryCreationThreshold";
172                     break;
173
174                 case ExceptionArgument.index:
175                     argumentName = "index";
176                     break;
177
178                 case ExceptionArgument.info:
179                     argumentName = "info";
180                     break;
181
182                 case ExceptionArgument.key:
183                     argumentName = "key";
184                     break;
185
186                 case ExceptionArgument.match:
187                     argumentName = "match";
188                     break;
189
190                 case ExceptionArgument.obj:
191                     argumentName = "obj";
192                     break;
193
194                 case ExceptionArgument.queue:
195                     argumentName = "queue";
196                     break;
197
198                 case ExceptionArgument.stack:
199                     argumentName = "stack";
200                     break;
201
202                 case ExceptionArgument.startIndex:
203                     argumentName = "startIndex";
204                     break;
205
206                 case ExceptionArgument.value:
207                     argumentName = "value";
208                     break;
209
210                 case ExceptionArgument.name:
211                     argumentName = "name";
212                     break;
213
214                 case ExceptionArgument.mode:
215                     argumentName = "mode";
216                     break;
217
218                 case ExceptionArgument.item:
219                     argumentName = "item";
220                     break;
221
222                 case ExceptionArgument.options:
223                     argumentName = "options";
224                     break;
225
226                 case ExceptionArgument.view:
227                     argumentName = "view";
228                     break;
229
230                case ExceptionArgument.sourceBytesToCopy:
231                     argumentName = "sourceBytesToCopy";
232                     break;
233
234                 default:
235                     Contract.Assert(false, "The enum value is not defined, please checked ExceptionArgumentName Enum.");
236                     return string.Empty;
237             }
238
239             return argumentName;
240         }
241
242         //
243         // This function will convert an ExceptionResource enum value to the resource string.
244         //
245         internal static string GetResourceName(ExceptionResource resource) {
246             string resourceName = null;
247
248             switch (resource) {
249                 case ExceptionResource.Argument_ImplementIComparable:
250                     resourceName = "Argument_ImplementIComparable";
251                     break;
252
253                 case ExceptionResource.Argument_AddingDuplicate:
254                     resourceName = "Argument_AddingDuplicate";
255                     break;
256
257                 case ExceptionResource.ArgumentOutOfRange_BiggerThanCollection:
258                     resourceName = "ArgumentOutOfRange_BiggerThanCollection";
259                     break;
260
261                 case ExceptionResource.ArgumentOutOfRange_Count:
262                     resourceName = "ArgumentOutOfRange_Count";
263                     break;
264
265                 case ExceptionResource.ArgumentOutOfRange_Index:
266                     resourceName = "ArgumentOutOfRange_Index";
267                     break;
268
269                 case ExceptionResource.ArgumentOutOfRange_InvalidThreshold:
270                     resourceName = "ArgumentOutOfRange_InvalidThreshold";
271                     break;
272
273                 case ExceptionResource.ArgumentOutOfRange_ListInsert:
274                     resourceName = "ArgumentOutOfRange_ListInsert";
275                     break;
276
277                 case ExceptionResource.ArgumentOutOfRange_NeedNonNegNum:
278                     resourceName = "ArgumentOutOfRange_NeedNonNegNum";
279                     break;
280
281                 case ExceptionResource.ArgumentOutOfRange_SmallCapacity:
282                     resourceName = "ArgumentOutOfRange_SmallCapacity";
283                     break;
284
285                 case ExceptionResource.Arg_ArrayPlusOffTooSmall:
286                     resourceName = "Arg_ArrayPlusOffTooSmall";
287                     break;
288
289                 case ExceptionResource.Arg_RankMultiDimNotSupported:
290                     resourceName = "Arg_RankMultiDimNotSupported";
291                     break;
292
293                 case ExceptionResource.Arg_NonZeroLowerBound:
294                     resourceName = "Arg_NonZeroLowerBound";
295                     break;
296
297                 case ExceptionResource.Argument_InvalidArrayType:
298                     resourceName = "Argument_InvalidArrayType";
299                     break;
300
301                 case ExceptionResource.Argument_InvalidOffLen:
302                     resourceName = "Argument_InvalidOffLen";
303                     break;
304
305                 case ExceptionResource.Argument_ItemNotExist:
306                     resourceName = "Argument_ItemNotExist";
307                     break;                    
308
309                 case ExceptionResource.InvalidOperation_CannotRemoveFromStackOrQueue:
310                     resourceName = "InvalidOperation_CannotRemoveFromStackOrQueue";
311                     break;
312
313                 case ExceptionResource.InvalidOperation_EmptyQueue:
314                     resourceName = "InvalidOperation_EmptyQueue";
315                     break;
316
317                 case ExceptionResource.InvalidOperation_EnumOpCantHappen:
318                     resourceName = "InvalidOperation_EnumOpCantHappen";
319                     break;
320
321                 case ExceptionResource.InvalidOperation_EnumFailedVersion:
322                     resourceName = "InvalidOperation_EnumFailedVersion";
323                     break;
324
325                 case ExceptionResource.InvalidOperation_EmptyStack:
326                     resourceName = "InvalidOperation_EmptyStack";
327                     break;
328
329                 case ExceptionResource.InvalidOperation_EnumNotStarted:
330                     resourceName = "InvalidOperation_EnumNotStarted";
331                     break;
332
333                 case ExceptionResource.InvalidOperation_EnumEnded:
334                     resourceName = "InvalidOperation_EnumEnded";
335                     break;
336
337                 case ExceptionResource.NotSupported_KeyCollectionSet:
338                     resourceName = "NotSupported_KeyCollectionSet";
339                     break;
340
341                 case ExceptionResource.NotSupported_ReadOnlyCollection:
342                     resourceName = "NotSupported_ReadOnlyCollection";
343                     break;
344
345                 case ExceptionResource.NotSupported_ValueCollectionSet:
346                     resourceName = "NotSupported_ValueCollectionSet";
347                     break;
348
349
350                 case ExceptionResource.NotSupported_SortedListNestedWrite:
351                     resourceName = "NotSupported_SortedListNestedWrite";
352                     break;
353
354
355                 case ExceptionResource.Serialization_InvalidOnDeser:
356                     resourceName = "Serialization_InvalidOnDeser";
357                     break;
358
359                 case ExceptionResource.Serialization_MissingKeys:
360                     resourceName = "Serialization_MissingKeys";
361                     break;
362
363                 case ExceptionResource.Serialization_NullKey:
364                     resourceName = "Serialization_NullKey";
365                     break;
366
367                 case ExceptionResource.Argument_InvalidType:
368                     resourceName = "Argument_InvalidType";
369                     break;
370
371                 case ExceptionResource.Argument_InvalidArgumentForComparison:
372                     resourceName = "Argument_InvalidArgumentForComparison";                    
373                     break;
374
375                 case ExceptionResource.InvalidOperation_NoValue:
376                     resourceName = "InvalidOperation_NoValue";                    
377                     break;
378
379                 case ExceptionResource.InvalidOperation_RegRemoveSubKey:
380                     resourceName = "InvalidOperation_RegRemoveSubKey";                    
381                     break;
382
383                 case ExceptionResource.Arg_RegSubKeyAbsent:
384                     resourceName = "Arg_RegSubKeyAbsent";                    
385                     break;
386
387                 case ExceptionResource.Arg_RegSubKeyValueAbsent:
388                     resourceName = "Arg_RegSubKeyValueAbsent";                    
389                     break;
390                     
391                 case ExceptionResource.Arg_RegKeyDelHive:
392                     resourceName = "Arg_RegKeyDelHive";                    
393                     break;
394
395                 case ExceptionResource.Security_RegistryPermission:
396                     resourceName = "Security_RegistryPermission";                    
397                     break;
398
399                 case ExceptionResource.Arg_RegSetStrArrNull:
400                     resourceName = "Arg_RegSetStrArrNull";                    
401                     break;
402
403                 case ExceptionResource.Arg_RegSetMismatchedKind:
404                     resourceName = "Arg_RegSetMismatchedKind";                    
405                     break;
406
407                 case ExceptionResource.UnauthorizedAccess_RegistryNoWrite:
408                     resourceName = "UnauthorizedAccess_RegistryNoWrite";
409                     break;
410
411                 case ExceptionResource.ObjectDisposed_RegKeyClosed:
412                     resourceName = "ObjectDisposed_RegKeyClosed";
413                     break;
414
415                 case ExceptionResource.Arg_RegKeyStrLenBug:
416                     resourceName = "Arg_RegKeyStrLenBug";
417                     break;
418
419                 case ExceptionResource.Argument_InvalidRegistryKeyPermissionCheck:
420                     resourceName = "Argument_InvalidRegistryKeyPermissionCheck";
421                     break;
422
423                 case ExceptionResource.NotSupported_InComparableType:
424                     resourceName = "NotSupported_InComparableType";
425                     break;
426
427                 case ExceptionResource.Argument_InvalidRegistryOptionsCheck:
428                     resourceName = "Argument_InvalidRegistryOptionsCheck";
429                     break;
430
431                 case ExceptionResource.Argument_InvalidRegistryViewCheck:
432                     resourceName = "Argument_InvalidRegistryViewCheck";
433                     break;
434
435                 default:
436                     Contract.Assert( false, "The enum value is not defined, please checked ExceptionArgumentName Enum.");
437                     return string.Empty;
438             }
439
440             return resourceName;
441         }
442
443     }
444
445     //
446     // The convention for this enum is using the argument name as the enum name
447     // 
448     internal enum ExceptionArgument {
449         obj,
450         dictionary,
451         dictionaryCreationThreshold,
452         array,
453         info,
454         key,
455         collection,
456         list,
457         match,
458         converter,
459         queue,
460         stack,
461         capacity,
462         index,
463         startIndex,
464         value,
465         count,
466         arrayIndex,
467         name,
468         mode,
469         item,
470         options,
471         view,
472         sourceBytesToCopy,
473 #if MONO
474         start,
475 #endif
476     }
477
478     //
479     // The convention for this enum is using the resource name as the enum name
480     // 
481     internal enum ExceptionResource {
482         Argument_ImplementIComparable,
483         Argument_InvalidType,     
484         Argument_InvalidArgumentForComparison,
485         Argument_InvalidRegistryKeyPermissionCheck,        
486         ArgumentOutOfRange_NeedNonNegNum,
487         
488         Arg_ArrayPlusOffTooSmall,
489         Arg_NonZeroLowerBound,        
490         Arg_RankMultiDimNotSupported,        
491         Arg_RegKeyDelHive,
492         Arg_RegKeyStrLenBug,  
493         Arg_RegSetStrArrNull,
494         Arg_RegSetMismatchedKind,
495         Arg_RegSubKeyAbsent,        
496         Arg_RegSubKeyValueAbsent,
497         
498         Argument_AddingDuplicate,
499         Serialization_InvalidOnDeser,
500         Serialization_MissingKeys,
501         Serialization_NullKey,
502         Argument_InvalidArrayType,
503         NotSupported_KeyCollectionSet,
504         NotSupported_ValueCollectionSet,
505         ArgumentOutOfRange_SmallCapacity,
506         ArgumentOutOfRange_Index,
507         Argument_InvalidOffLen,
508         Argument_ItemNotExist,
509         ArgumentOutOfRange_Count,
510         ArgumentOutOfRange_InvalidThreshold,
511         ArgumentOutOfRange_ListInsert,
512         NotSupported_ReadOnlyCollection,
513         InvalidOperation_CannotRemoveFromStackOrQueue,
514         InvalidOperation_EmptyQueue,
515         InvalidOperation_EnumOpCantHappen,
516         InvalidOperation_EnumFailedVersion,
517         InvalidOperation_EmptyStack,
518         ArgumentOutOfRange_BiggerThanCollection,
519         InvalidOperation_EnumNotStarted,
520         InvalidOperation_EnumEnded,
521         NotSupported_SortedListNestedWrite,
522         InvalidOperation_NoValue,
523         InvalidOperation_RegRemoveSubKey,
524         Security_RegistryPermission,
525         UnauthorizedAccess_RegistryNoWrite,
526         ObjectDisposed_RegKeyClosed,
527         NotSupported_InComparableType,
528         Argument_InvalidRegistryOptionsCheck,
529         Argument_InvalidRegistryViewCheck
530     }
531 }
532