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