Run check for unused fields only when compilation succeeded
[mono.git] / mcs / mcs / module.cs
1 //
2 // module.cs: keeps a tree representation of the generated code
3 //
4 // Authors: Miguel de Icaza (miguel@gnu.org)
5 //          Marek Safar  (marek.safar@gmail.com)
6 //
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
8 //
9 // Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 // Copyright 2003-2008 Novell, Inc.
11 // Copyright 2011 Xamarin Inc
12 //
13
14 using System;
15 using System.Collections.Generic;
16 using System.Runtime.InteropServices;
17 using Mono.CompilerServices.SymbolWriter;
18 using System.Linq;
19
20 #if STATIC
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
23 #else
24 using System.Reflection;
25 using System.Reflection.Emit;
26 #endif
27
28 namespace Mono.CSharp
29 {
30         //
31         // Module (top-level type) container
32         //
33         public sealed class ModuleContainer : TypeContainer
34         {
35 #if STATIC
36                 //
37                 // Compiler generated container for static data
38                 //
39                 sealed class StaticDataContainer : CompilerGeneratedClass
40                 {
41                         readonly Dictionary<int, Struct> size_types;
42                         new int fields;
43
44                         public StaticDataContainer (ModuleContainer module)
45                                 : base (module, new MemberName ("<PrivateImplementationDetails>" + module.builder.ModuleVersionId.ToString ("B"), Location.Null), Modifiers.STATIC)
46                         {
47                                 size_types = new Dictionary<int, Struct> ();
48                         }
49
50                         public override void CloseContainer ()
51                         {
52                                 base.CloseContainer ();
53
54                                 foreach (var entry in size_types) {
55                                         entry.Value.CloseContainer ();
56                                 }
57                         }
58
59                         public FieldSpec DefineInitializedData (byte[] data, Location loc)
60                         {
61                                 Struct size_type;
62                                 if (!size_types.TryGetValue (data.Length, out size_type)) {
63                                         //
64                                         // Build common type for this data length. We cannot use
65                                         // DefineInitializedData because it creates public type,
66                                         // and its name is not unique among modules
67                                         //
68                                         size_type = new Struct (this, new MemberName ("$ArrayType=" + data.Length, loc), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, null);
69                                         size_type.CreateContainer ();
70                                         size_type.DefineContainer ();
71
72                                         size_types.Add (data.Length, size_type);
73
74                                         // It has to work even if StructLayoutAttribute does not exist
75                                         size_type.TypeBuilder.__SetLayout (1, data.Length);
76                                 }
77
78                                 var name = "$field-" + fields.ToString ("X");
79                                 ++fields;
80                                 const Modifiers fmod = Modifiers.STATIC | Modifiers.INTERNAL;
81                                 var fbuilder = TypeBuilder.DefineField (name, size_type.CurrentType.GetMetaInfo (), ModifiersExtensions.FieldAttr (fmod) | FieldAttributes.HasFieldRVA);
82                                 fbuilder.__SetDataAndRVA (data);
83
84                                 return new FieldSpec (CurrentType, null, size_type.CurrentType, fbuilder, fmod);
85                         }
86                 }
87
88                 StaticDataContainer static_data;
89
90                 //
91                 // Makes const data field inside internal type container
92                 //
93                 public FieldSpec MakeStaticData (byte[] data, Location loc)
94                 {
95                         if (static_data == null) {
96                                 static_data = new StaticDataContainer (this);
97                                 static_data.CreateContainer ();
98                                 static_data.DefineContainer ();
99
100                                 AddCompilerGeneratedClass (static_data);
101                         }
102
103                         return static_data.DefineInitializedData (data, loc);
104                 }
105 #endif
106
107                 public CharSet? DefaultCharSet;
108                 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
109
110                 readonly Dictionary<int, List<AnonymousTypeClass>> anonymous_types;
111                 readonly Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> array_types;
112                 readonly Dictionary<TypeSpec, PointerContainer> pointer_types;
113                 readonly Dictionary<TypeSpec, ReferenceContainer> reference_types;
114                 readonly Dictionary<TypeSpec, MethodSpec> attrs_cache;
115
116                 AssemblyDefinition assembly;
117                 readonly CompilerContext context;
118                 readonly RootNamespace global_ns;
119                 readonly Dictionary<string, RootNamespace> alias_ns;
120
121                 ModuleBuilder builder;
122
123                 bool has_extenstion_method;
124
125                 PredefinedAttributes predefined_attributes;
126                 PredefinedTypes predefined_types;
127                 PredefinedMembers predefined_members;
128
129                 static readonly string[] attribute_targets = new string[] { "assembly", "module" };
130
131                 public ModuleContainer (CompilerContext context)
132                         : base (null, MemberName.Null, null, 0)
133                 {
134                         this.context = context;
135
136                         caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected);
137
138                         containers = new List<TypeContainer> ();
139                         anonymous_types = new Dictionary<int, List<AnonymousTypeClass>> ();
140                         global_ns = new GlobalRootNamespace ();
141                         alias_ns = new Dictionary<string, RootNamespace> ();
142                         array_types = new Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ();
143                         pointer_types = new Dictionary<TypeSpec, PointerContainer> ();
144                         reference_types = new Dictionary<TypeSpec, ReferenceContainer> ();
145                         attrs_cache = new Dictionary<TypeSpec, MethodSpec> ();
146                 }
147
148                 #region Properties
149
150                 internal Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ArrayTypesCache {
151                         get {
152                                 return array_types;
153                         }
154                 }
155
156                 //
157                 // Cache for parameter-less attributes
158                 //
159                 internal Dictionary<TypeSpec, MethodSpec> AttributeConstructorCache {
160                         get {
161                                 return attrs_cache;
162                         }
163                 }
164
165                 public override AttributeTargets AttributeTargets {
166                         get {
167                                 return AttributeTargets.Assembly;
168                         }
169                 }
170
171                 public ModuleBuilder Builder {
172                         get {
173                                 return builder;
174                         }
175                 }
176
177                 public override CompilerContext Compiler {
178                         get {
179                                 return context;
180                         }
181                 }
182
183                 public AssemblyDefinition DeclaringAssembly {
184                         get {
185                                 return assembly;
186                         }
187                 }
188
189                 internal DocumentationBuilder DocumentationBuilder {
190                         get; set;
191                 }
192
193                 public override string DocCommentHeader {
194                         get {
195                                 throw new NotSupportedException ();
196                         }
197                 }
198
199                 public Evaluator Evaluator {
200                         get; set;
201                 }
202
203                 public bool HasDefaultCharSet {
204                         get {
205                                 return DefaultCharSet.HasValue;
206                         }
207                 }
208
209                 public bool HasExtensionMethod {
210                         get {
211                                 return has_extenstion_method;
212                         }
213                         set {
214                                 has_extenstion_method = value;
215                         }
216                 }
217
218                 public bool HasTypesFullyDefined {
219                         get; set;
220                 }
221
222                 //
223                 // Returns module global:: namespace
224                 //
225                 public RootNamespace GlobalRootNamespace {
226                     get {
227                         return global_ns;
228                     }
229                 }
230
231                 public override ModuleContainer Module {
232                         get {
233                                 return this;
234                         }
235                 }
236
237                 internal Dictionary<TypeSpec, PointerContainer> PointerTypesCache {
238                         get {
239                                 return pointer_types;
240                         }
241                 }
242
243                 internal PredefinedAttributes PredefinedAttributes {
244                         get {
245                                 return predefined_attributes;
246                         }
247                 }
248
249                 internal PredefinedMembers PredefinedMembers {
250                         get {
251                                 return predefined_members;
252                         }
253                 }
254
255                 internal PredefinedTypes PredefinedTypes {
256                         get {
257                                 return predefined_types;
258                         }
259                 }
260
261                 internal Dictionary<TypeSpec, ReferenceContainer> ReferenceTypesCache {
262                         get {
263                                 return reference_types;
264                         }
265                 }
266
267                 public override string[] ValidAttributeTargets {
268                         get {
269                                 return attribute_targets;
270                         }
271                 }
272
273                 #endregion
274
275                 public override void Accept (StructuralVisitor visitor)
276                 {
277                         visitor.Visit (this);
278                 }
279
280                 public void AddAnonymousType (AnonymousTypeClass type)
281                 {
282                         List<AnonymousTypeClass> existing;
283                         if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing))
284                         if (existing == null) {
285                                 existing = new List<AnonymousTypeClass> ();
286                                 anonymous_types.Add (type.Parameters.Count, existing);
287                         }
288
289                         existing.Add (type);
290                 }
291
292                 public void AddAttribute (Attribute attr, IMemberContext context)
293                 {
294                         attr.AttachTo (this, context);
295
296                         if (attributes == null) {
297                                 attributes = new Attributes (attr);
298                                 return;
299                         }
300
301                         attributes.AddAttribute (attr);
302                 }
303
304                 public override void AddTypeContainer (TypeContainer tc)
305                 {
306                         containers.Add (tc);
307                 }
308
309                 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
310                 {
311                         if (a.Target == AttributeTargets.Assembly) {
312                                 assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
313                                 return;
314                         }
315
316                         if (a.Type == pa.DefaultCharset) {
317                                 switch (a.GetCharSetValue ()) {
318                                 case CharSet.Ansi:
319                                 case CharSet.None:
320                                         break;
321                                 case CharSet.Auto:
322                                         DefaultCharSet = CharSet.Auto;
323                                         DefaultCharSetType = TypeAttributes.AutoClass;
324                                         break;
325                                 case CharSet.Unicode:
326                                         DefaultCharSet = CharSet.Unicode;
327                                         DefaultCharSetType = TypeAttributes.UnicodeClass;
328                                         break;
329                                 default:
330                                         Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid",
331                                                 a.GetSignatureForError ());
332                                         break;
333                                 }
334                         } else if (a.Type == pa.CLSCompliant) {
335                                 Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
336                                 if (cls == null) {
337                                         Report.Warning (3012, 1, a.Location,
338                                                 "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
339                                 } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) {
340                                         Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ());
341                                         Report.Warning (3017, 1, a.Location,
342                                                 "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
343                                         return;
344                                 }
345                         }
346
347                         builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
348                 }
349
350                 public override void CloseContainer ()
351                 {
352                         if (anonymous_types != null) {
353                                 foreach (var atypes in anonymous_types)
354                                         foreach (var at in atypes.Value)
355                                                 at.CloseContainer ();
356                         }
357
358                         base.CloseContainer ();
359                 }
360
361                 public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
362                 {
363                         return builder.DefineType (name, attr, null, typeSize);
364                 }
365
366                 //
367                 // Creates alias global namespace
368                 //
369                 public RootNamespace CreateRootNamespace (string alias)
370                 {
371                         if (alias == global_ns.Alias) {
372                                 RootNamespace.Error_GlobalNamespaceRedefined (Report, Location.Null);
373                                 return global_ns;
374                         }
375
376                         RootNamespace rn;
377                         if (!alias_ns.TryGetValue (alias, out rn)) {
378                                 rn = new RootNamespace (alias);
379                                 alias_ns.Add (alias, rn);
380                         }
381
382                         return rn;
383                 }
384
385                 public void Create (AssemblyDefinition assembly, ModuleBuilder moduleBuilder)
386                 {
387                         this.assembly = assembly;
388                         builder = moduleBuilder;
389                 }
390
391                 public override bool Define ()
392                 {
393                         DefineContainer ();
394
395                         base.Define ();
396
397                         HasTypesFullyDefined = true;
398
399                         return true;
400                 }
401
402                 public override bool DefineContainer ()
403                 {
404                         DefineNamespace ();
405
406                         return base.DefineContainer ();
407                 }
408
409                 public override void EmitContainer ()
410                 {
411                         if (OptAttributes != null)
412                                 OptAttributes.Emit ();
413
414                         if (Compiler.Settings.Unsafe) {
415                                 var pa = PredefinedAttributes.UnverifiableCode;
416                                 if (pa.IsDefined)
417                                         pa.EmitAttribute (builder);
418                         }
419
420                         foreach (var tc in containers) {
421                                 tc.DefineConstants ();
422                         }
423
424                         base.EmitContainer ();
425
426                         if (Compiler.Report.Errors == 0)
427                                 VerifyMembers ();
428
429                         if (anonymous_types != null) {
430                                 foreach (var atypes in anonymous_types)
431                                         foreach (var at in atypes.Value)
432                                                 at.EmitContainer ();
433                         }
434                 }
435
436                 internal override void GenerateDocComment (DocumentationBuilder builder)
437                 {
438                         foreach (var tc in containers)
439                                 tc.GenerateDocComment (builder);
440                 }
441
442                 public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
443                 {
444                         List<AnonymousTypeClass> candidates;
445                         if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
446                                 return null;
447
448                         int i;
449                         foreach (AnonymousTypeClass at in candidates) {
450                                 for (i = 0; i < parameters.Count; ++i) {
451                                         if (!parameters [i].Equals (at.Parameters [i]))
452                                                 break;
453                                 }
454
455                                 if (i == parameters.Count)
456                                         return at;
457                         }
458
459                         return null;
460                 }
461
462                 public override void GetCompletionStartingWith (string prefix, List<string> results)
463                 {
464                         var names = Evaluator.GetVarNames ();
465                         results.AddRange (names.Where (l => l.StartsWith (prefix)));
466                 }
467
468                 public RootNamespace GetRootNamespace (string name)
469                 {
470                         RootNamespace rn;
471                         alias_ns.TryGetValue (name, out rn);
472                         return rn;
473                 }
474
475                 public override string GetSignatureForError ()
476                 {
477                         return "<module>";
478                 }
479
480                 public void InitializePredefinedTypes ()
481                 {
482                         predefined_attributes = new PredefinedAttributes (this);
483                         predefined_types = new PredefinedTypes (this);
484                         predefined_members = new PredefinedMembers (this);
485                 }
486
487                 public override bool IsClsComplianceRequired ()
488                 {
489                         return DeclaringAssembly.IsCLSCompliant;
490                 }
491
492                 public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
493                 {
494                         Attribute a = OptAttributes.Search ("assembly", a_type);
495                         if (a != null) {
496                                 a.Resolve ();
497                         }
498                         return a;
499                 }
500
501                 public void SetDeclaringAssembly (AssemblyDefinition assembly)
502                 {
503                         // TODO: This setter is quite ugly but I have not found a way around it yet
504                         this.assembly = assembly;
505                 }
506         }
507 }