Merge all static runtime libs into libmono-static.
[mono.git] / mcs / mcs / context.cs
1 //
2 // context.cs: Various compiler contexts.
3 //
4 // Author:
5 //   Marek Safar (marek.safar@gmail.com)
6 //   Miguel de Icaza (miguel@ximian.com)
7 //
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2004-2009 Novell, Inc.
10 // Copyright 2011 Xamarin Inc.
11 //
12
13 using System;
14 using System.Collections.Generic;
15 using System.IO;
16 using System.Security.Cryptography;
17 using System.Diagnostics;
18
19 namespace Mono.CSharp
20 {
21         public enum LookupMode
22         {
23                 Normal = 0,
24                 Probing = 1,
25                 IgnoreAccessibility = 2,
26                 IgnoreStaticUsing = 1 << 10
27         }
28
29         //
30         // Implemented by elements which can act as independent contexts
31         // during resolve phase. Used mostly for lookups.
32         //
33         public interface IMemberContext : IModuleContext
34         {
35                 //
36                 // A scope type context, it can be inflated for generic types
37                 //
38                 TypeSpec CurrentType { get; }
39
40                 //
41                 // A scope type parameters either VAR or MVAR
42                 //
43                 TypeParameters CurrentTypeParameters { get; }
44
45                 //
46                 // A member definition of the context. For partial types definition use
47                 // CurrentTypeDefinition.PartialContainer otherwise the context is local
48                 //
49                 // TODO: Obsolete it in this context, dynamic context cannot guarantee sensible value
50                 //
51                 MemberCore CurrentMemberDefinition { get; }
52
53                 bool IsObsolete { get; }
54                 bool IsUnsafe { get; }
55                 bool IsStatic { get; }
56
57                 string GetSignatureForError ();
58
59                 ExtensionMethodCandidates LookupExtensionMethod (string name, int arity);
60                 FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc);
61                 FullNamedExpression LookupNamespaceAlias (string name);
62         }
63
64         public interface IModuleContext
65         {
66                 ModuleContainer Module { get; }
67         }
68
69         //
70         // Block or statement resolving context
71         //
72         public class BlockContext : ResolveContext
73         {
74                 readonly TypeSpec return_type;
75
76                 //
77                 // Tracks the last offset used by VariableInfo
78                 //
79                 public int AssignmentInfoOffset;
80
81                 public BlockContext (IMemberContext mc, ExplicitBlock block, TypeSpec returnType)
82                         : base (mc)
83                 {
84                         if (returnType == null)
85                                 throw new ArgumentNullException ("returnType");
86
87                         this.return_type = returnType;
88
89                         // TODO: check for null value
90                         CurrentBlock = block;
91                 }
92
93                 public BlockContext (ResolveContext rc, ExplicitBlock block, TypeSpec returnType)
94                         : this (rc.MemberContext, block, returnType)
95                 {
96                         if (rc.IsUnsafe)
97                                 flags |= ResolveContext.Options.UnsafeScope;
98
99                         if (rc.HasSet (ResolveContext.Options.CheckedScope))
100                                 flags |= ResolveContext.Options.CheckedScope;
101
102                         if (!rc.ConstantCheckState)
103                                 flags &= ~Options.ConstantCheckState;
104
105                         if (rc.IsInProbingMode)
106                                 flags |= ResolveContext.Options.ProbingMode;
107
108                         if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
109                                 flags |= ResolveContext.Options.FieldInitializerScope;
110
111                         if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
112                                 flags |= ResolveContext.Options.ExpressionTreeConversion;
113
114                         if (rc.HasSet (ResolveContext.Options.BaseInitializer))
115                                 flags |= ResolveContext.Options.BaseInitializer;
116
117                         if (rc.HasSet (ResolveContext.Options.QueryClauseScope))
118                                 flags |= ResolveContext.Options.QueryClauseScope;
119                 }
120
121                 public ExceptionStatement CurrentTryBlock { get; set; }
122
123                 public TryCatch CurrentTryCatch { get; set; }
124
125                 public LoopStatement EnclosingLoop { get; set; }
126
127                 public LoopStatement EnclosingLoopOrSwitch { get; set; }
128
129                 public Switch Switch { get; set; }
130
131                 public TypeSpec ReturnType {
132                         get { return return_type; }
133                 }
134         }
135
136         //
137         // Expression resolving context
138         //
139         public class ResolveContext : IMemberContext
140         {
141                 [Flags]
142                 public enum Options
143                 {
144                         /// <summary>
145                         ///   This flag tracks the `checked' state of the compilation,
146                         ///   it controls whether we should generate code that does overflow
147                         ///   checking, or if we generate code that ignores overflows.
148                         ///
149                         ///   The default setting comes from the command line option to generate
150                         ///   checked or unchecked code plus any source code changes using the
151                         ///   checked/unchecked statements or expressions.   Contrast this with
152                         ///   the ConstantCheckState flag.
153                         /// </summary>
154                         CheckedScope = 1 << 0,
155
156                         /// <summary>
157                         ///   The constant check state is always set to `true' and cant be changed
158                         ///   from the command line.  The source code can change this setting with
159                         ///   the `checked' and `unchecked' statements and expressions. 
160                         /// </summary>
161                         ConstantCheckState = 1 << 1,
162
163                         AllCheckStateFlags = CheckedScope | ConstantCheckState,
164
165                         //
166                         // unsafe { ... } scope
167                         //
168                         UnsafeScope = 1 << 2,
169                         CatchScope = 1 << 3,
170                         FinallyScope = 1 << 4,
171                         FieldInitializerScope = 1 << 5,
172                         CompoundAssignmentScope = 1 << 6,
173                         FixedInitializerScope = 1 << 7,
174                         BaseInitializer = 1 << 8,
175
176                         //
177                         // Inside an enum definition, we do not resolve enumeration values
178                         // to their enumerations, but rather to the underlying type/value
179                         // This is so EnumVal + EnumValB can be evaluated.
180                         //
181                         // There is no "E operator + (E x, E y)", so during an enum evaluation
182                         // we relax the rules
183                         //
184                         EnumScope = 1 << 9,
185
186                         ConstantScope = 1 << 10,
187
188                         ConstructorScope = 1 << 11,
189
190                         UsingInitializerScope = 1 << 12,
191
192                         LockScope = 1 << 13,
193
194                         TryScope = 1 << 14,
195
196                         TryWithCatchScope = 1 << 15,
197
198                         DontSetConditionalAccessReceiver = 1 << 16,
199
200                         NameOfScope = 1 << 17,
201
202                         QueryClauseScope = 1 << 18,
203
204                         ///
205                         /// Indicates the current context is in probing mode, no errors are reported. 
206                         ///
207                         ProbingMode = 1 << 22,
208
209                         //
210                         // Return and ContextualReturn statements will set the ReturnType
211                         // value based on the expression types of each return statement
212                         // instead of the method return type which is initially null.
213                         //
214                         InferReturnType = 1 << 23,
215
216                         OmitDebuggingInfo = 1 << 24,
217
218                         ExpressionTreeConversion = 1 << 25,
219
220                         InvokeSpecialName = 1 << 26
221                 }
222
223                 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
224                 // it's public so that we can use a struct at the callsite
225                 public struct FlagsHandle : IDisposable
226                 {
227                         readonly ResolveContext ec;
228                         readonly Options invmask, oldval;
229
230                         public FlagsHandle (ResolveContext ec, Options flagsToSet)
231                                 : this (ec, flagsToSet, flagsToSet)
232                         {
233                         }
234
235                         internal FlagsHandle (ResolveContext ec, Options mask, Options val)
236                         {
237                                 this.ec = ec;
238                                 invmask = ~mask;
239                                 oldval = ec.flags & mask;
240                                 ec.flags = (ec.flags & invmask) | (val & mask);
241
242 //                              if ((mask & Options.ProbingMode) != 0)
243 //                                      ec.Report.DisableReporting ();
244                         }
245
246                         public void Dispose ()
247                         {
248 //                              if ((invmask & Options.ProbingMode) == 0)
249 //                                      ec.Report.EnableReporting ();
250
251                                 ec.flags = (ec.flags & invmask) | oldval;
252                         }
253                 }
254
255                 protected Options flags;
256
257                 //
258                 // Whether we are inside an anonymous method.
259                 //
260                 public AnonymousExpression CurrentAnonymousMethod;
261
262                 //
263                 // Holds a varible used during collection or object initialization.
264                 //
265                 public Expression CurrentInitializerVariable;
266
267                 public Block CurrentBlock;
268
269                 public readonly IMemberContext MemberContext;
270
271                 public ResolveContext (IMemberContext mc)
272                 {
273                         if (mc == null)
274                                 throw new ArgumentNullException ();
275
276                         MemberContext = mc;
277
278                         //
279                         // The default setting comes from the command line option
280                         //
281                         if (mc.Module.Compiler.Settings.Checked)
282                                 flags |= Options.CheckedScope;
283
284                         //
285                         // The constant check state is always set to true
286                         //
287                         flags |= Options.ConstantCheckState;
288                 }
289
290                 public ResolveContext (IMemberContext mc, Options options)
291                         : this (mc)
292                 {
293                         flags |= options;
294                 }
295
296                 #region Properties
297
298                 public BuiltinTypes BuiltinTypes {
299                         get {
300                                 return MemberContext.Module.Compiler.BuiltinTypes;
301                         }
302                 }
303
304                 public virtual ExplicitBlock ConstructorBlock {
305                         get {
306                                 return CurrentBlock.Explicit;
307                         }
308                 }
309
310                 //
311                 // The current iterator
312                 //
313                 public Iterator CurrentIterator {
314                         get { return CurrentAnonymousMethod as Iterator; }
315                 }
316
317                 public TypeSpec CurrentType {
318                         get { return MemberContext.CurrentType; }
319                 }
320
321                 public TypeParameters CurrentTypeParameters {
322                         get { return MemberContext.CurrentTypeParameters; }
323                 }
324
325                 public MemberCore CurrentMemberDefinition {
326                         get { return MemberContext.CurrentMemberDefinition; }
327                 }
328
329                 public bool ConstantCheckState {
330                         get { return (flags & Options.ConstantCheckState) != 0; }
331                 }
332
333                 public bool IsInProbingMode {
334                         get {
335                                 return (flags & Options.ProbingMode) != 0;
336                         }
337                 }
338
339                 public bool IsObsolete {
340                         get {
341                                 // Disables obsolete checks when probing is on
342                                 return MemberContext.IsObsolete;
343                         }
344                 }
345
346                 public bool IsStatic {
347                         get {
348                                 return MemberContext.IsStatic;
349                         }
350                 }
351
352                 public bool IsUnsafe {
353                         get {
354                                 return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe;
355                         }
356                 }
357
358                 public bool IsRuntimeBinder {
359                         get {
360                                 return Module.Compiler.IsRuntimeBinder;
361                         }
362                 }
363
364                 public bool IsVariableCapturingRequired {
365                         get {
366                                 return !IsInProbingMode;
367                         }
368                 }
369
370                 public ModuleContainer Module {
371                         get {
372                                 return MemberContext.Module;
373                         }
374                 }
375
376                 public Report Report {
377                         get {
378                                 return Module.Compiler.Report;
379                         }
380                 }
381
382                 #endregion
383
384                 public bool MustCaptureVariable (INamedBlockVariable local)
385                 {
386                         if (CurrentAnonymousMethod == null)
387                                 return false;
388
389                         //
390                         // Capture only if this or any of child blocks contain yield
391                         // or it's a parameter
392                         //
393                         if (CurrentAnonymousMethod.IsIterator)
394                                 return local.IsParameter || local.Block.Explicit.HasYield;
395
396                         //
397                         // Capture only if this or any of child blocks contain await
398                         // or it's a parameter or we need to access variable from 
399                         // different parameter block
400                         //
401                         if (CurrentAnonymousMethod is AsyncInitializer)
402                                 return local.IsParameter || local.Block.Explicit.HasAwait || CurrentBlock.Explicit.HasAwait ||
403                                         local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
404
405                         return local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
406                 }
407
408                 public bool HasSet (Options options)
409                 {
410                         return (this.flags & options) == options;
411                 }
412
413                 public bool HasAny (Options options)
414                 {
415                         return (this.flags & options) != 0;
416                 }
417
418
419                 // Temporarily set all the given flags to the given value.  Should be used in an 'using' statement
420                 public FlagsHandle Set (Options options)
421                 {
422                         return new FlagsHandle (this, options);
423                 }
424
425                 public FlagsHandle With (Options options, bool enable)
426                 {
427                         return new FlagsHandle (this, options, enable ? options : 0);
428                 }
429
430                 #region IMemberContext Members
431
432                 public string GetSignatureForError ()
433                 {
434                         return MemberContext.GetSignatureForError ();
435                 }
436
437                 public ExtensionMethodCandidates LookupExtensionMethod (string name, int arity)
438                 {
439                         return MemberContext.LookupExtensionMethod (name, arity);
440                 }
441
442                 public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
443                 {
444                         return MemberContext.LookupNamespaceOrType (name, arity, mode, loc);
445                 }
446
447                 public FullNamedExpression LookupNamespaceAlias (string name)
448                 {
449                         return MemberContext.LookupNamespaceAlias (name);
450                 }
451
452                 #endregion
453         }
454
455         public class FlowAnalysisContext
456         {
457                 readonly CompilerContext ctx;
458
459                 public FlowAnalysisContext (CompilerContext ctx, ParametersBlock parametersBlock, int definiteAssignmentLength)
460                 {
461                         this.ctx = ctx;
462                         this.ParametersBlock = parametersBlock;
463
464                         DefiniteAssignment = definiteAssignmentLength == 0 ?
465                                 DefiniteAssignmentBitSet.Empty :
466                                 new DefiniteAssignmentBitSet (definiteAssignmentLength);
467                 }
468
469                 public DefiniteAssignmentBitSet DefiniteAssignment { get; set; }
470
471                 public DefiniteAssignmentBitSet DefiniteAssignmentOnTrue { get; set; }
472
473                 public DefiniteAssignmentBitSet DefiniteAssignmentOnFalse { get; set; }
474
475                 Dictionary<Statement, List<DefiniteAssignmentBitSet>> LabelStack { get; set; }
476
477                 public ParametersBlock ParametersBlock { get; set; }
478
479                 public Report Report {
480                         get {
481                                 return ctx.Report;
482                         }
483                 }
484
485                 public DefiniteAssignmentBitSet SwitchInitialDefinitiveAssignment { get; set; }
486
487                 public TryFinally TryFinally { get; set; }
488
489                 public bool UnreachableReported { get; set; }
490
491                 public bool AddReachedLabel (Statement label)
492                 {
493                         List<DefiniteAssignmentBitSet> das;
494                         if (LabelStack == null) {
495                                 LabelStack = new Dictionary<Statement, List<DefiniteAssignmentBitSet>> ();
496                                 das = null;
497                         } else {
498                                 LabelStack.TryGetValue (label, out das);
499                         }
500
501                         if (das == null) {
502                                 das = new List<DefiniteAssignmentBitSet> ();
503                                 das.Add (new DefiniteAssignmentBitSet (DefiniteAssignment));
504                                 LabelStack.Add (label, das);
505                                 return false;
506                         }
507
508                         foreach (var existing in das) {
509                                 if (DefiniteAssignmentBitSet.IsIncluded (existing, DefiniteAssignment))
510                                         return true;
511                         }
512
513                         if (DefiniteAssignment == DefiniteAssignmentBitSet.Empty)
514                                 das.Add (DefiniteAssignment);
515                         else
516                                 das.Add (new DefiniteAssignmentBitSet (DefiniteAssignment));
517
518                         return false;
519                 }
520
521                 public DefiniteAssignmentBitSet BranchDefiniteAssignment ()
522                 {
523                         return BranchDefiniteAssignment (DefiniteAssignment);
524                 }
525
526                 public DefiniteAssignmentBitSet BranchDefiniteAssignment (DefiniteAssignmentBitSet da)
527                 {
528                         if (da != DefiniteAssignmentBitSet.Empty) {
529                                 DefiniteAssignment = new DefiniteAssignmentBitSet (da);
530                         }
531
532                         return da;
533                 }
534
535                 public Dictionary<Statement, List<DefiniteAssignmentBitSet>> CopyLabelStack ()
536                 {
537                         if (LabelStack == null)
538                                 return null;
539
540                         var dest = new Dictionary<Statement, List<DefiniteAssignmentBitSet>> ();
541                         foreach (var entry in LabelStack) {
542                                 dest.Add (entry.Key, new List<DefiniteAssignmentBitSet> (entry.Value));
543                         }
544
545                         return dest;
546                 }
547
548                 public bool IsDefinitelyAssigned (VariableInfo variable)
549                 {
550                         return variable.IsAssigned (DefiniteAssignment);
551                 }
552
553                 public bool IsStructFieldDefinitelyAssigned (VariableInfo variable, string name)
554                 {
555                         return variable.IsStructFieldAssigned (DefiniteAssignment, name);
556                 }
557
558                 public void SetLabelStack (Dictionary<Statement, List<DefiniteAssignmentBitSet>> labelStack)
559                 {
560                         LabelStack = labelStack;
561                 }
562
563                 public void SetVariableAssigned (VariableInfo variable, bool generatedAssignment = false)
564                 {
565                         variable.SetAssigned (DefiniteAssignment, generatedAssignment);
566                 }
567
568                 public void SetVariableAssigned (VariableInfo variable, DefiniteAssignmentBitSet da)
569                 {
570                         variable.SetAssigned (da, false);
571                 }
572
573                 public void SetStructFieldAssigned (VariableInfo variable, string name)
574                 {
575                         variable.SetStructFieldAssigned (DefiniteAssignment, name);
576                 }
577         }
578
579
580         //
581         // This class is used during the Statement.Clone operation
582         // to remap objects that have been cloned.
583         //
584         // Since blocks are cloned by Block.Clone, we need a way for
585         // expressions that must reference the block to be cloned
586         // pointing to the new cloned block.
587         //
588         public class CloneContext
589         {
590                 Dictionary<Block, Block> block_map = new Dictionary<Block, Block> ();
591
592                 public void AddBlockMap (Block from, Block to)
593                 {
594                         block_map.Add (from, to);
595                 }
596
597                 public Block LookupBlock (Block from)
598                 {
599                         Block result;
600                         if (!block_map.TryGetValue (from, out result)) {
601                                 result = (Block) from.Clone (this);
602                         }
603
604                         return result;
605                 }
606
607                 ///
608                 /// Remaps block to cloned copy if one exists.
609                 ///
610                 public Block RemapBlockCopy (Block from)
611                 {
612                         Block mapped_to;
613                         if (!block_map.TryGetValue (from, out mapped_to))
614                                 return from;
615
616                         return mapped_to;
617                 }
618         }
619
620         //
621         // Main compiler context
622         //
623         public class CompilerContext
624         {
625                 static readonly TimeReporter DisabledTimeReporter = new TimeReporter (false);
626
627                 readonly Report report;
628                 readonly BuiltinTypes builtin_types;
629                 readonly CompilerSettings settings;
630
631                 Dictionary<string, SourceFile> all_source_files;
632
633                 public CompilerContext (CompilerSettings settings, ReportPrinter reportPrinter)
634                 {
635                         this.settings = settings;
636                         this.report = new Report (this, reportPrinter);
637                         this.builtin_types = new BuiltinTypes ();
638                         this.TimeReporter = DisabledTimeReporter;
639                 }
640
641                 #region Properties
642
643                 public BuiltinTypes BuiltinTypes {
644                         get {
645                                 return builtin_types;
646                         }
647                 }
648
649                 // Used for special handling of runtime dynamic context mostly
650                 // by error reporting but also by member accessibility checks
651                 public bool IsRuntimeBinder {
652                         get; set;
653                 }
654
655                 public Report Report {
656                         get {
657                                 return report;
658                         }
659                 }
660
661                 public CompilerSettings Settings {
662                         get {
663                                 return settings;
664                         }
665                 }
666
667                 public List<SourceFile> SourceFiles {
668                         get {
669                                 return settings.SourceFiles;
670                         }
671                 }
672
673                 internal TimeReporter TimeReporter {
674                         get; set;
675                 }
676
677                 #endregion
678
679                 //
680                 // This is used when we encounter a #line preprocessing directive during parsing
681                 // to register additional source file names
682                 //
683                 public SourceFile LookupFile (CompilationSourceFile comp_unit, string name)
684                 {
685                         if (all_source_files == null) {
686                                 all_source_files = new Dictionary<string, SourceFile> ();
687                                 foreach (var source in SourceFiles)
688                                         all_source_files[source.OriginalFullPathName] = source;
689                         }
690
691                         string path;
692                         if (!Path.IsPathRooted (name)) {
693                                 var loc = comp_unit.SourceFile;
694                                 string root = Path.GetDirectoryName (loc.OriginalFullPathName);
695                                 path = Path.GetFullPath (Path.Combine (root, name));
696                                 var dir = Path.GetDirectoryName (loc.Name);
697                                 if (!string.IsNullOrEmpty (dir))
698                                         name = Path.Combine (dir, name);
699                         } else
700                                 path = name;
701
702                         SourceFile retval;
703                         if (all_source_files.TryGetValue (path, out retval))
704                                 return retval;
705
706                         retval = new SourceFile (name, path, all_source_files.Count + 1);
707                         Location.AddFile (retval);
708                         all_source_files.Add (path, retval);
709                         return retval;
710                 }
711         }
712
713         //
714         // Generic code emitter context
715         //
716         public class BuilderContext
717         {
718                 [Flags]
719                 public enum Options
720                 {
721                         /// <summary>
722                         ///   This flag tracks the `checked' state of the compilation,
723                         ///   it controls whether we should generate code that does overflow
724                         ///   checking, or if we generate code that ignores overflows.
725                         ///
726                         ///   The default setting comes from the command line option to generate
727                         ///   checked or unchecked code plus any source code changes using the
728                         ///   checked/unchecked statements or expressions.   Contrast this with
729                         ///   the ConstantCheckState flag.
730                         /// </summary>
731                         CheckedScope = 1 << 0,
732
733                         AccurateDebugInfo = 1 << 1,
734
735                         OmitDebugInfo = 1 << 2,
736
737                         ConstructorScope = 1 << 3,
738
739                         AsyncBody = 1 << 4,
740                 }
741
742                 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
743                 // it's public so that we can use a struct at the callsite
744                 public struct FlagsHandle : IDisposable
745                 {
746                         readonly BuilderContext ec;
747                         readonly Options invmask, oldval;
748
749                         public FlagsHandle (BuilderContext ec, Options flagsToSet)
750                                 : this (ec, flagsToSet, flagsToSet)
751                         {
752                         }
753
754                         internal FlagsHandle (BuilderContext ec, Options mask, Options val)
755                         {
756                                 this.ec = ec;
757                                 invmask = ~mask;
758                                 oldval = ec.flags & mask;
759                                 ec.flags = (ec.flags & invmask) | (val & mask);
760                         }
761
762                         public void Dispose ()
763                         {
764                                 ec.flags = (ec.flags & invmask) | oldval;
765                         }
766                 }
767
768                 protected Options flags;
769
770                 public bool HasSet (Options options)
771                 {
772                         return (this.flags & options) == options;
773                 }
774
775                 // Temporarily set all the given flags to the given value.  Should be used in an 'using' statement
776                 public FlagsHandle With (Options options, bool enable)
777                 {
778                         return new FlagsHandle (this, options, enable ? options : 0);
779                 }
780         }
781
782         //
783         // Parser session objects. We could recreate all these objects for each parser
784         // instance but the best parser performance the session object can be reused
785         //
786         public class ParserSession
787         {
788                 MD5 md5;
789
790                 public readonly char[] StreamReaderBuffer = new char[SeekableStreamReader.DefaultReadAheadSize * 2];
791                 public readonly Dictionary<char[], string>[] Identifiers = new Dictionary<char[], string>[Tokenizer.MaxIdentifierLength + 1];
792                 public readonly List<Parameter> ParametersStack = new List<Parameter> (4);
793                 public readonly char[] IDBuilder = new char[Tokenizer.MaxIdentifierLength];
794                 public readonly char[] NumberBuilder = new char[Tokenizer.MaxNumberLength];
795
796                 public LocationsBag LocationsBag { get; set; }
797                 public bool UseJayGlobalArrays { get; set; }
798                 public LocatedToken[] LocatedTokens { get; set; }
799
800                 public MD5 GetChecksumAlgorithm ()
801                 {
802                         return md5 ?? (md5 = MD5.Create ());
803                 }
804         }
805 }