Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2817-BinPackingSpeedup/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Parser/mcs/assembly.cs

Last change on this file was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

File size: 36.4 KB
Line 
1//
2// assembly.cs: Assembly declaration and specifications
3//
4// Authors:
5//   Miguel de Icaza (miguel@ximian.com)
6//   Marek Safar (marek.safar@gmail.com)
7//
8// Copyright 2001, 2002, 2003 Ximian, Inc.
9// Copyright 2004-2011 Novell, Inc.
10// Copyright 2011-2013 Xamarin Inc
11//
12
13
14using System;
15using System.IO;
16using System.Collections.Generic;
17using System.Globalization;
18using System.Security;
19using System.Security.Cryptography;
20using System.Security.Permissions;
21using Mono.Security.Cryptography;
22using Mono.CompilerServices.SymbolWriter;
23
24#if STATIC
25using IKVM.Reflection;
26using IKVM.Reflection.Emit;
27using SecurityType = System.Collections.Generic.List<IKVM.Reflection.Emit.CustomAttributeBuilder>;
28#else
29using SecurityType = System.Collections.Generic.Dictionary<System.Security.Permissions.SecurityAction, System.Security.PermissionSet>;
30using System.Reflection;
31using System.Reflection.Emit;
32#endif
33
34namespace Mono.CSharp
35{
36  public interface IAssemblyDefinition
37  {
38    string FullName { get; }
39    bool IsCLSCompliant { get; }
40    bool IsMissing { get; }
41    string Name { get; }
42
43    byte[] GetPublicKeyToken ();
44    bool IsFriendAssemblyTo (IAssemblyDefinition assembly);
45  }
46               
47  public abstract class AssemblyDefinition : IAssemblyDefinition
48  {
49    // TODO: make it private and move all builder based methods here
50    public AssemblyBuilder Builder;
51    protected AssemblyBuilderExtension builder_extra;
52    MonoSymbolFile symbol_writer;
53
54    bool is_cls_compliant;
55    bool wrap_non_exception_throws;
56    bool wrap_non_exception_throws_custom;
57    bool has_user_debuggable;
58
59    protected ModuleContainer module;
60    readonly string name;
61    protected readonly string file_name;
62
63    byte[] public_key, public_key_token;
64    bool delay_sign;
65
66    // Holds private/public key pair when private key
67    // was available
68    StrongNameKeyPair private_key; 
69
70    Attribute cls_attribute;
71    Method entry_point;
72
73    protected List<ImportedModuleDefinition> added_modules;
74    SecurityType declarative_security;
75    Dictionary<ITypeDefinition, Attribute> emitted_forwarders;
76    AssemblyAttributesPlaceholder module_target_attrs;
77
78    // Win32 version info values
79    string vi_product, vi_product_version, vi_company, vi_copyright, vi_trademark;
80
81    protected AssemblyDefinition (ModuleContainer module, string name)
82    {
83      this.module = module;
84      this.name = Path.GetFileNameWithoutExtension (name);
85
86      wrap_non_exception_throws = true;
87
88      delay_sign = Compiler.Settings.StrongNameDelaySign;
89
90      //
91      // Load strong name key early enough for assembly importer to be able to
92      // use the keys for InternalsVisibleTo
93      // This should go somewhere close to ReferencesLoading but don't have the place yet
94      //
95      if (Compiler.Settings.HasKeyFileOrContainer) {
96        LoadPublicKey (Compiler.Settings.StrongNameKeyFile, Compiler.Settings.StrongNameKeyContainer);
97      }
98    }
99
100    protected AssemblyDefinition (ModuleContainer module, string name, string fileName)
101      : this (module, name)
102    {
103      this.file_name = fileName;
104    }
105
106    #region Properties
107
108    public Attribute CLSCompliantAttribute {
109      get {
110        return cls_attribute;
111      }
112    }
113
114    public CompilerContext Compiler {
115      get {
116        return module.Compiler;
117      }
118    }
119
120    //
121    // Assembly entry point, aka Main method
122    //
123    public Method EntryPoint {
124      get {
125        return entry_point;
126      }
127      set {
128        entry_point = value;
129      }
130    }
131
132    public string FullName {
133      get {
134        return Builder.FullName;
135      }
136    }
137
138    public bool HasCLSCompliantAttribute {
139      get {
140        return cls_attribute != null;
141      }
142    }
143
144    // TODO: This should not exist here but will require more changes
145    public MetadataImporter Importer {
146        get; set;
147    }
148
149    public bool IsCLSCompliant {
150      get {
151        return is_cls_compliant;
152      }
153    }
154
155    bool IAssemblyDefinition.IsMissing {
156      get {
157        return false;
158      }
159    }
160
161    public bool IsSatelliteAssembly { get; private set; }
162
163    public string Name {
164      get {
165        return name;
166      }
167    }
168
169    public bool WrapNonExceptionThrows {
170      get {
171        return wrap_non_exception_throws;
172      }
173    }
174
175    protected Report Report {
176      get {
177        return Compiler.Report;
178      }
179    }
180
181    public MonoSymbolFile SymbolWriter {
182      get {
183        return symbol_writer;
184      }
185    }
186
187    #endregion
188
189    public void AddModule (ImportedModuleDefinition module)
190    {
191      if (added_modules == null) {
192        added_modules = new List<ImportedModuleDefinition> ();
193        added_modules.Add (module);
194      }
195    }
196
197    public void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
198    {
199      if (a.IsValidSecurityAttribute ()) {
200        a.ExtractSecurityPermissionSet (ctor, ref declarative_security);
201        return;
202      }
203
204      if (a.Type == pa.AssemblyCulture) {
205        string value = a.GetString ();
206        if (value == null || value.Length == 0)
207          return;
208
209        if (Compiler.Settings.Target == Target.Exe) {
210          Report.Error (7059, a.Location, "Executables cannot be satellite assemblies. Remove the attribute or keep it empty");
211          return;
212        }
213
214        if (value == "neutral")
215          value = "";
216
217        if (Compiler.Settings.Target == Target.Module) {
218          SetCustomAttribute (ctor, cdata);
219        } else {
220          builder_extra.SetCulture (value, a.Location);
221        }
222
223        IsSatelliteAssembly = true;
224        return;
225      }
226
227      if (a.Type == pa.AssemblyVersion) {
228        string value = a.GetString ();
229        if (value == null || value.Length == 0)
230          return;
231
232        var vinfo = IsValidAssemblyVersion (value, true);
233        if (vinfo == null) {
234          Report.Error (7034, a.Location, "The specified version string `{0}' does not conform to the required format - major[.minor[.build[.revision]]]",
235            value);
236          return;
237        }
238
239        if (Compiler.Settings.Target == Target.Module) {
240          SetCustomAttribute (ctor, cdata);
241        } else {
242          builder_extra.SetVersion (vinfo, a.Location);
243        }
244
245        return;
246      }
247
248      if (a.Type == pa.AssemblyAlgorithmId) {
249        const int pos = 2; // skip CA header
250        uint alg = (uint) cdata [pos];
251        alg |= ((uint) cdata [pos + 1]) << 8;
252        alg |= ((uint) cdata [pos + 2]) << 16;
253        alg |= ((uint) cdata [pos + 3]) << 24;
254
255        if (Compiler.Settings.Target == Target.Module) {
256          SetCustomAttribute (ctor, cdata);
257        } else {
258          builder_extra.SetAlgorithmId (alg, a.Location);
259        }
260
261        return;
262      }
263
264      if (a.Type == pa.AssemblyFlags) {
265        const int pos = 2; // skip CA header
266        uint flags = (uint) cdata[pos];
267        flags |= ((uint) cdata [pos + 1]) << 8;
268        flags |= ((uint) cdata [pos + 2]) << 16;
269        flags |= ((uint) cdata [pos + 3]) << 24;
270
271        // Ignore set PublicKey flag if assembly is not strongnamed
272        if ((flags & (uint) AssemblyNameFlags.PublicKey) != 0 && public_key == null)
273          flags &= ~(uint) AssemblyNameFlags.PublicKey;
274
275        if (Compiler.Settings.Target == Target.Module) {
276          SetCustomAttribute (ctor, cdata);
277        } else {
278          builder_extra.SetFlags (flags, a.Location);
279        }
280
281        return;
282      }
283
284      if (a.Type == pa.TypeForwarder) {
285        TypeSpec t = a.GetArgumentType ();
286        if (t == null || TypeManager.HasElementType (t)) {
287          Report.Error (735, a.Location, "Invalid type specified as an argument for TypeForwardedTo attribute");
288          return;
289        }
290
291        if (emitted_forwarders == null) {
292          emitted_forwarders = new Dictionary<ITypeDefinition, Attribute> ();
293        } else if (emitted_forwarders.ContainsKey (t.MemberDefinition)) {
294          Report.SymbolRelatedToPreviousError (emitted_forwarders[t.MemberDefinition].Location, null);
295          Report.Error (739, a.Location, "A duplicate type forward of type `{0}'",
296            t.GetSignatureForError ());
297          return;
298        }
299
300        emitted_forwarders.Add (t.MemberDefinition, a);
301
302        if (t.MemberDefinition.DeclaringAssembly == this) {
303          Report.SymbolRelatedToPreviousError (t);
304          Report.Error (729, a.Location, "Cannot forward type `{0}' because it is defined in this assembly",
305            t.GetSignatureForError ());
306          return;
307        }
308
309        if (t.IsNested) {
310          Report.Error (730, a.Location, "Cannot forward type `{0}' because it is a nested type",
311            t.GetSignatureForError ());
312          return;
313        }
314
315        builder_extra.AddTypeForwarder (t.GetDefinition (), a.Location);
316        return;
317      }
318
319      if (a.Type == pa.Extension) {
320        a.Error_MisusedExtensionAttribute ();
321        return;
322      }
323
324      if (a.Type == pa.InternalsVisibleTo) {
325        string assembly_name = a.GetString ();
326        if (assembly_name == null) {
327          Report.Error (7030, a.Location, "Friend assembly reference cannot have `null' value");
328          return;
329        }
330
331        if (assembly_name.Length == 0)
332          return;
333#if STATIC
334        ParsedAssemblyName aname;
335        ParseAssemblyResult r = Fusion.ParseAssemblyName (assembly_name, out aname);
336        if (r != ParseAssemblyResult.OK) {
337          Report.Warning (1700, 3, a.Location, "Friend assembly reference `{0}' is invalid and cannot be resolved",
338            assembly_name);
339          return;
340        }
341
342        if (aname.Version != null || aname.Culture != null || aname.ProcessorArchitecture != ProcessorArchitecture.None) {
343          Report.Error (1725, a.Location,
344            "Friend assembly reference `{0}' is invalid. InternalsVisibleTo declarations cannot have a version, culture or processor architecture specified",
345            assembly_name);
346
347          return;
348        }
349
350        if (public_key != null && !aname.HasPublicKey) {
351          Report.Error (1726, a.Location,
352            "Friend assembly reference `{0}' is invalid. Strong named assemblies must specify a public key in their InternalsVisibleTo declarations",
353            assembly_name);
354          return;
355        }
356#endif
357      } else if (a.Type == pa.RuntimeCompatibility) {
358        wrap_non_exception_throws_custom = true;
359      } else if (a.Type == pa.AssemblyFileVersion) {
360        vi_product_version = a.GetString ();
361        if (string.IsNullOrEmpty (vi_product_version) || IsValidAssemblyVersion (vi_product_version, false) == null) {
362          Report.Warning (7035, 1, a.Location, "The specified version string `{0}' does not conform to the recommended format major.minor.build.revision",
363            vi_product_version, a.Name);
364          return;
365        }
366
367        // File version info decoding from blob is not supported
368        var cab = new CustomAttributeBuilder ((ConstructorInfo) ctor.GetMetaInfo (), new object[] { vi_product_version });
369        Builder.SetCustomAttribute (cab);
370        return;
371      } else if (a.Type == pa.AssemblyProduct) {
372        vi_product = a.GetString ();
373      } else if (a.Type == pa.AssemblyCompany) {
374        vi_company = a.GetString ();
375      } else if (a.Type == pa.AssemblyDescription) {
376        // TODO: Needs extra api
377      } else if (a.Type == pa.AssemblyCopyright) {
378        vi_copyright = a.GetString ();
379      } else if (a.Type == pa.AssemblyTrademark) {
380        vi_trademark = a.GetString ();
381      } else if (a.Type == pa.Debuggable) {
382        has_user_debuggable = true;
383      }
384
385      SetCustomAttribute (ctor, cdata);
386    }
387
388    //
389    // When using assembly public key attributes InternalsVisibleTo key
390    // was not checked, we have to do it later when we actually know what
391    // our public key token is
392    //
393    void CheckReferencesPublicToken ()
394    {
395      // TODO: It should check only references assemblies but there is
396      // no working SRE API
397      foreach (var entry in Importer.Assemblies) {
398        var a = entry as ImportedAssemblyDefinition;
399        if (a == null || a.IsMissing)
400          continue;
401
402        if (public_key != null && !a.HasStrongName) {
403          Report.Error (1577, "Referenced assembly `{0}' does not have a strong name",
404            a.FullName);
405        }
406
407        var ci = a.Assembly.GetName ().CultureInfo;
408        if (!ci.Equals (CultureInfo.InvariantCulture)) {
409          Report.Warning (8009, 1, "Referenced assembly `{0}' has different culture setting of `{1}'",
410            a.Name, ci.Name);
411        }
412
413        if (!a.IsFriendAssemblyTo (this))
414          continue;
415
416        var attr = a.GetAssemblyVisibleToName (this);
417        var atoken = attr.GetPublicKeyToken ();
418
419        if (ArrayComparer.IsEqual (GetPublicKeyToken (), atoken))
420          continue;
421
422        Report.SymbolRelatedToPreviousError (a.Location);
423        Report.Error (281,
424          "Friend access was granted to `{0}', but the output assembly is named `{1}'. Try adding a reference to `{0}' or change the output assembly name to match it",
425          attr.FullName, FullName);
426      }
427    }
428
429    protected AssemblyName CreateAssemblyName ()
430    {
431      var an = new AssemblyName (name);
432
433      if (public_key != null && Compiler.Settings.Target != Target.Module) {
434        if (delay_sign) {
435          an.SetPublicKey (public_key);
436        } else {
437          if (public_key.Length == 16) {
438            Report.Error (1606, "Could not sign the assembly. ECMA key can only be used to delay-sign assemblies");
439          } else if (private_key == null) {
440            Error_AssemblySigning ("The specified key file does not have a private key");
441          } else {
442            an.KeyPair = private_key;
443          }
444        }
445      }
446
447      return an;
448    }
449
450    public virtual ModuleBuilder CreateModuleBuilder ()
451    {
452      if (file_name == null)
453        throw new NotSupportedException ("transient module in static assembly");
454
455      var module_name = Path.GetFileName (file_name);
456
457      // Always initialize module without symbolInfo. We could be framework dependent
458      // but returned ISymbolWriter does not have all what we need therefore some
459      // adaptor will be needed for now we alwayas emit MDB format when generating
460      // debug info
461      return Builder.DefineDynamicModule (module_name, module_name, false);
462    }
463
464    public virtual void Emit ()
465    {
466      if (Compiler.Settings.Target == Target.Module) {
467        module_target_attrs = new AssemblyAttributesPlaceholder (module, name);
468        module_target_attrs.CreateContainer ();
469        module_target_attrs.DefineContainer ();
470        module_target_attrs.Define ();
471        module.AddCompilerGeneratedClass (module_target_attrs);
472      } else if (added_modules != null) {
473        ReadModulesAssemblyAttributes ();
474      }
475
476      if (Compiler.Settings.GenerateDebugInfo) {
477        symbol_writer = new MonoSymbolFile ();
478      }
479
480      module.EmitContainer ();
481
482      if (module.HasExtensionMethod) {
483        var pa = module.PredefinedAttributes.Extension;
484        if (pa.IsDefined) {
485          SetCustomAttribute (pa.Constructor, AttributeEncoder.Empty);
486        }
487      }
488
489      if (!IsSatelliteAssembly) {
490        if (!has_user_debuggable && Compiler.Settings.GenerateDebugInfo) {
491          var pa = module.PredefinedAttributes.Debuggable;
492          if (pa.IsDefined) {
493            var modes = System.Diagnostics.DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints;
494            if (!Compiler.Settings.Optimize)
495              modes |= System.Diagnostics.DebuggableAttribute.DebuggingModes.DisableOptimizations;
496
497            pa.EmitAttribute (Builder, modes);
498          }
499        }
500
501        if (!wrap_non_exception_throws_custom) {
502          PredefinedAttribute pa = module.PredefinedAttributes.RuntimeCompatibility;
503          if (pa.IsDefined && pa.ResolveBuilder ()) {
504            var prop = module.PredefinedMembers.RuntimeCompatibilityWrapNonExceptionThrows.Get ();
505            if (prop != null) {
506              AttributeEncoder encoder = new AttributeEncoder ();
507              encoder.EncodeNamedPropertyArgument (prop, new BoolLiteral (Compiler.BuiltinTypes, true, Location.Null));
508              SetCustomAttribute (pa.Constructor, encoder.ToArray ());
509            }
510          }
511        }
512
513        if (declarative_security != null) {
514#if STATIC
515          foreach (var entry in declarative_security) {
516            Builder.__AddDeclarativeSecurity (entry);
517          }
518#else
519          throw new NotSupportedException ("Assembly-level security");
520#endif
521        }
522      }
523
524      CheckReferencesPublicToken ();
525
526      SetEntryPoint ();
527    }
528
529    public byte[] GetPublicKeyToken ()
530    {
531      if (public_key == null || public_key_token != null)
532        return public_key_token;
533
534      HashAlgorithm ha = SHA1.Create ();
535      byte[] hash = ha.ComputeHash (public_key);
536      // we need the last 8 bytes in reverse order
537      public_key_token = new byte[8];
538      Buffer.BlockCopy (hash, hash.Length - 8, public_key_token, 0, 8);
539      Array.Reverse (public_key_token, 0, 8);
540      return public_key_token;
541    }
542
543    //
544    // Either keyFile or keyContainer has to be non-null
545    //
546    void LoadPublicKey (string keyFile, string keyContainer)
547    {
548      if (keyContainer != null) {
549        try {
550          private_key = new StrongNameKeyPair (keyContainer);
551          public_key = private_key.PublicKey;
552        } catch {
553          Error_AssemblySigning ("The specified key container `" + keyContainer + "' does not exist");
554        }
555
556        return;
557      }
558
559      bool key_file_exists = File.Exists (keyFile);
560
561      //
562      // For attribute based KeyFile do additional lookup
563      // in output assembly path
564      //
565      if (!key_file_exists && Compiler.Settings.StrongNameKeyFile == null) {
566        //
567        // The key file can be relative to output assembly
568        //
569        string test_path = Path.Combine (Path.GetDirectoryName (file_name), keyFile);
570        key_file_exists = File.Exists (test_path);
571        if (key_file_exists)
572          keyFile = test_path;
573      }
574
575      if (!key_file_exists) {
576        Error_AssemblySigning ("The specified key file `" + keyFile + "' does not exist");
577        return;
578      }
579
580      using (FileStream fs = new FileStream (keyFile, FileMode.Open, FileAccess.Read)) {
581        byte[] snkeypair = new byte[fs.Length];
582        fs.Read (snkeypair, 0, snkeypair.Length);
583
584        // check for ECMA key
585        if (snkeypair.Length == 16) {
586          public_key = snkeypair;
587          return;
588        }
589
590        try {
591          // take it, with or without, a private key
592          RSA rsa = CryptoConvert.FromCapiKeyBlob (snkeypair);
593          // and make sure we only feed the public part to Sys.Ref
594          byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
595
596          // AssemblyName.SetPublicKey requires an additional header
597          byte[] publicKeyHeader = new byte[8] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00 };
598
599          // Encode public key
600          public_key = new byte[12 + publickey.Length];
601          Buffer.BlockCopy (publicKeyHeader, 0, public_key, 0, publicKeyHeader.Length);
602
603          // Length of Public Key (in bytes)
604          int lastPart = public_key.Length - 12;
605          public_key[8] = (byte) (lastPart & 0xFF);
606          public_key[9] = (byte) ((lastPart >> 8) & 0xFF);
607          public_key[10] = (byte) ((lastPart >> 16) & 0xFF);
608          public_key[11] = (byte) ((lastPart >> 24) & 0xFF);
609
610          Buffer.BlockCopy (publickey, 0, public_key, 12, publickey.Length);
611        } catch {
612          Error_AssemblySigning ("The specified key file `" + keyFile + "' has incorrect format");
613          return;
614        }
615
616        if (delay_sign)
617          return;
618
619        try {
620          // TODO: Is there better way to test for a private key presence ?
621          CryptoConvert.FromCapiPrivateKeyBlob (snkeypair);
622          private_key = new StrongNameKeyPair (snkeypair);
623        } catch { }
624      }
625    }
626
627    void ReadModulesAssemblyAttributes ()
628    {
629      foreach (var m in added_modules) {
630        var cattrs = m.ReadAssemblyAttributes ();
631        if (cattrs == null)
632          continue;
633
634        module.OptAttributes.AddAttributes (cattrs);
635      }
636    }
637
638    public void Resolve ()
639    {
640      if (Compiler.Settings.Unsafe && module.PredefinedTypes.SecurityAction.Define ()) {
641        //
642        // Emits [assembly: SecurityPermissionAttribute (SecurityAction.RequestMinimum, SkipVerification = true)]
643        // when -unsafe option was specified
644        //
645        Location loc = Location.Null;
646
647        MemberAccess system_security_permissions = new MemberAccess (new MemberAccess (
648          new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Security", loc), "Permissions", loc);
649
650        var req_min = module.PredefinedMembers.SecurityActionRequestMinimum.Resolve (loc);
651
652        Arguments pos = new Arguments (1);
653        pos.Add (new Argument (req_min.GetConstant (null)));
654
655        Arguments named = new Arguments (1);
656        named.Add (new NamedArgument ("SkipVerification", loc, new BoolLiteral (Compiler.BuiltinTypes, true, loc)));
657
658        Attribute g = new Attribute ("assembly",
659          new MemberAccess (system_security_permissions, "SecurityPermissionAttribute"),
660          new Arguments[] { pos, named }, loc, false);
661        g.AttachTo (module, module);
662
663        // Disable no-location warnings (e.g. obsolete) for compiler generated attribute
664        Compiler.Report.DisableReporting ();
665        try {
666          var ctor = g.Resolve ();
667          if (ctor != null) {
668            g.ExtractSecurityPermissionSet (ctor, ref declarative_security);
669          }
670        } finally {
671          Compiler.Report.EnableReporting ();
672        }
673      }
674
675      if (module.OptAttributes == null)
676        return;
677
678      // Ensure that we only have GlobalAttributes, since the Search isn't safe with other types.
679      if (!module.OptAttributes.CheckTargets())
680        return;
681
682      cls_attribute = module.ResolveAssemblyAttribute (module.PredefinedAttributes.CLSCompliant);
683
684      if (cls_attribute != null) {
685        is_cls_compliant = cls_attribute.GetClsCompliantAttributeValue ();
686      }
687
688      if (added_modules != null && Compiler.Settings.VerifyClsCompliance && is_cls_compliant) {
689        foreach (var m in added_modules) {
690          if (!m.IsCLSCompliant) {
691            Report.Error (3013,
692              "Added modules must be marked with the CLSCompliant attribute to match the assembly",
693              m.Name);
694          }
695        }
696      }
697
698      Attribute a = module.ResolveAssemblyAttribute (module.PredefinedAttributes.RuntimeCompatibility);
699      if (a != null) {
700        var val = a.GetNamedValue ("WrapNonExceptionThrows") as BoolConstant;
701        if (val != null)
702          wrap_non_exception_throws = val.Value;
703      }
704    }
705
706    protected void ResolveAssemblySecurityAttributes ()
707    {
708      string key_file = null;
709      string key_container = null;
710
711      if (module.OptAttributes != null) {
712        foreach (Attribute a in module.OptAttributes.Attrs) {
713          // cannot rely on any resolve-based members before you call Resolve
714          if (a.ExplicitTarget != "assembly")
715            continue;
716
717          // TODO: This code is buggy: comparing Attribute name without resolving is wrong.
718          //       However, this is invoked by CodeGen.Init, when none of the namespaces
719          //       are loaded yet.
720          // TODO: Does not handle quoted attributes properly
721          switch (a.Name) {
722          case "AssemblyKeyFile":
723          case "AssemblyKeyFileAttribute":
724          case "System.Reflection.AssemblyKeyFileAttribute":
725            if (Compiler.Settings.StrongNameKeyFile != null) {
726              Report.SymbolRelatedToPreviousError (a.Location, a.GetSignatureForError ());
727              Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
728                  "keyfile", "System.Reflection.AssemblyKeyFileAttribute");
729            } else {
730              string value = a.GetString ();
731              if (!string.IsNullOrEmpty (value)) {
732                Error_ObsoleteSecurityAttribute (a, "keyfile");
733                key_file = value;
734              }
735            }
736            break;
737          case "AssemblyKeyName":
738          case "AssemblyKeyNameAttribute":
739          case "System.Reflection.AssemblyKeyNameAttribute":
740            if (Compiler.Settings.StrongNameKeyContainer != null) {
741              Report.SymbolRelatedToPreviousError (a.Location, a.GetSignatureForError ());
742              Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
743                  "keycontainer", "System.Reflection.AssemblyKeyNameAttribute");
744            } else {
745              string value = a.GetString ();
746              if (!string.IsNullOrEmpty (value)) {
747                Error_ObsoleteSecurityAttribute (a, "keycontainer");
748                key_container = value;
749              }
750            }
751            break;
752          case "AssemblyDelaySign":
753          case "AssemblyDelaySignAttribute":
754          case "System.Reflection.AssemblyDelaySignAttribute":
755            bool b = a.GetBoolean ();
756            if (b) {
757              Error_ObsoleteSecurityAttribute (a, "delaysign");
758            }
759
760            delay_sign = b;
761            break;
762          }
763        }
764      }
765
766      // We came here only to report assembly attributes warnings
767      if (public_key != null)
768        return;
769
770      //
771      // Load the strong key file found in attributes when no
772      // command line key was given
773      //
774      if (key_file != null || key_container != null) {
775        LoadPublicKey (key_file, key_container);
776      } else if (delay_sign) {
777        Report.Warning (1607, 1, "Delay signing was requested but no key file was given");
778      }
779    }
780
781    public void EmbedResources ()
782    {
783      //
784      // Add Win32 resources
785      //
786      if (Compiler.Settings.Win32ResourceFile != null) {
787        Builder.DefineUnmanagedResource (Compiler.Settings.Win32ResourceFile);
788      } else {
789        Builder.DefineVersionInfoResource (vi_product, vi_product_version, vi_company, vi_copyright, vi_trademark);
790      }
791
792      if (Compiler.Settings.Win32IconFile != null) {
793        builder_extra.DefineWin32IconResource (Compiler.Settings.Win32IconFile);
794      }
795
796      if (Compiler.Settings.Resources != null) {
797        if (Compiler.Settings.Target == Target.Module) {
798          Report.Error (1507, "Cannot link resource file when building a module");
799        } else {
800          int counter = 0;
801          foreach (var res in Compiler.Settings.Resources) {
802            if (!File.Exists (res.FileName)) {
803              Report.Error (1566, "Error reading resource file `{0}'", res.FileName);
804              continue;
805            }
806
807            if (res.IsEmbeded) {
808              Stream stream;
809              if (counter++ < 10) {
810                stream = File.OpenRead (res.FileName);
811              } else {
812                // TODO: SRE API requires resource stream to be available during AssemblyBuilder::Save
813                // we workaround it by reading everything into memory to compile projects with
814                // many embedded resource (over 3500) references
815                stream = new MemoryStream (File.ReadAllBytes (res.FileName));
816              }
817
818              module.Builder.DefineManifestResource (res.Name, stream, res.Attributes);
819            } else {
820              Builder.AddResourceFile (res.Name, Path.GetFileName (res.FileName), res.Attributes);
821            }
822          }
823        }
824      }
825    }
826
827    public void Save ()
828    {
829      PortableExecutableKinds pekind = PortableExecutableKinds.ILOnly;
830      ImageFileMachine machine;
831
832      switch (Compiler.Settings.Platform) {
833      case Platform.X86:
834        pekind |= PortableExecutableKinds.Required32Bit;
835        machine = ImageFileMachine.I386;
836        break;
837      case Platform.X64:
838        pekind |= PortableExecutableKinds.PE32Plus;
839        machine = ImageFileMachine.AMD64;
840        break;
841      case Platform.IA64:
842        machine = ImageFileMachine.IA64;
843        break;
844      case Platform.AnyCPU32Preferred:
845#if STATIC
846        pekind |= PortableExecutableKinds.Preferred32Bit;
847        machine = ImageFileMachine.I386;
848        break;
849#else
850        throw new NotSupportedException ();
851#endif
852      case Platform.Arm:
853#if STATIC
854        machine = ImageFileMachine.ARM;
855        break;
856#else
857        throw new NotSupportedException ();
858#endif
859      case Platform.AnyCPU:
860      default:
861        machine = ImageFileMachine.I386;
862        break;
863      }
864
865      Compiler.TimeReporter.Start (TimeReporter.TimerType.OutputSave);
866      try {
867        if (Compiler.Settings.Target == Target.Module) {
868          SaveModule (pekind, machine);
869        } else {
870          Builder.Save (module.Builder.ScopeName, pekind, machine);
871        }
872      } catch (Exception e) {
873        Report.Error (16, "Could not write to file `" + name + "', cause: " + e.Message);
874      }
875      Compiler.TimeReporter.Stop (TimeReporter.TimerType.OutputSave);
876
877      // Save debug symbols file
878      if (symbol_writer != null && Compiler.Report.Errors == 0) {
879        // TODO: it should run in parallel
880        Compiler.TimeReporter.Start (TimeReporter.TimerType.DebugSave);
881
882        var filename = file_name + ".mdb";
883        try {
884          // We mmap the file, so unlink the previous version since it may be in use
885          File.Delete (filename);
886        } catch {
887          // We can safely ignore
888        }
889
890        module.WriteDebugSymbol (symbol_writer);
891
892        using (FileStream fs = new FileStream (filename, FileMode.Create, FileAccess.Write)) {
893          symbol_writer.CreateSymbolFile (module.Builder.ModuleVersionId, fs);
894        }
895
896        Compiler.TimeReporter.Stop (TimeReporter.TimerType.DebugSave);
897      }
898    }
899
900    protected virtual void SaveModule (PortableExecutableKinds pekind, ImageFileMachine machine)
901    {
902      Report.RuntimeMissingSupport (Location.Null, "-target:module");
903    }
904
905    void SetCustomAttribute (MethodSpec ctor, byte[] data)
906    {
907      if (module_target_attrs != null)
908        module_target_attrs.AddAssemblyAttribute (ctor, data);
909      else
910        Builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), data);
911    }
912
913    void SetEntryPoint ()
914    {
915      if (!Compiler.Settings.NeedsEntryPoint) {
916        if (Compiler.Settings.MainClass != null)
917          Report.Error (2017, "Cannot specify -main if building a module or library");
918
919        return;
920      }
921
922      PEFileKinds file_kind;
923
924      switch (Compiler.Settings.Target) {
925      case Target.Library:
926      case Target.Module:
927        file_kind = PEFileKinds.Dll;
928        break;
929      case Target.WinExe:
930        file_kind = PEFileKinds.WindowApplication;
931        break;
932      default:
933        file_kind = PEFileKinds.ConsoleApplication;
934        break;
935      }
936
937      if (entry_point == null) {
938        string main_class = Compiler.Settings.MainClass;
939        if (main_class != null) {
940          // TODO: Handle dotted names
941          var texpr = module.GlobalRootNamespace.LookupType (module, main_class, 0, LookupMode.Probing, Location.Null);
942          if (texpr == null) {
943            Report.Error (1555, "Could not find `{0}' specified for Main method", main_class);
944            return;
945          }
946
947          var mtype = texpr.MemberDefinition as ClassOrStruct;
948          if (mtype == null) {
949            Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", main_class);
950            return;
951          }
952
953          Report.Error (1558, mtype.Location, "`{0}' does not have a suitable static Main method", mtype.GetSignatureForError ());
954        } else {
955          string pname = file_name == null ? name : Path.GetFileName (file_name);
956          Report.Error (5001, "Program `{0}' does not contain a static `Main' method suitable for an entry point",
957            pname);
958        }
959
960        return;
961      }
962
963      Builder.SetEntryPoint (entry_point.MethodBuilder, file_kind);
964    }
965
966    void Error_ObsoleteSecurityAttribute (Attribute a, string option)
967    {
968      Report.Warning (1699, 1, a.Location,
969        "Use compiler option `{0}' or appropriate project settings instead of `{1}' attribute",
970        option, a.Name);
971    }
972
973    void Error_AssemblySigning (string text)
974    {
975      Report.Error (1548, "Error during assembly signing. " + text);
976    }
977
978    public bool IsFriendAssemblyTo (IAssemblyDefinition assembly)
979    {
980      return false;
981    }
982
983    static Version IsValidAssemblyVersion (string version, bool allowGenerated)
984    {
985      string[] parts = version.Split ('.');
986      if (parts.Length < 1 || parts.Length > 4)
987        return null;
988
989      var values = new int[4];
990      for (int i = 0; i < parts.Length; ++i) {
991        if (!int.TryParse (parts[i], out values[i])) {
992          if (parts[i].Length == 1 && parts[i][0] == '*' && allowGenerated) {
993            if (i == 2) {
994              // Nothing can follow *
995              if (parts.Length > 3)
996                return null;
997
998              // Generate Build value based on days since 1/1/2000
999              TimeSpan days = DateTime.Today - new DateTime (2000, 1, 1);
1000              values[i] = System.Math.Max (days.Days, 0);
1001              i = 3;
1002            }
1003
1004            if (i == 3) {
1005              // Generate Revision value based on every other second today
1006              var seconds = DateTime.Now - DateTime.Today;
1007              values[i] = (int) seconds.TotalSeconds / 2;
1008              continue;
1009            }
1010          }
1011
1012          return null;
1013        }
1014
1015        if (values[i] > ushort.MaxValue)
1016          return null;
1017      }
1018
1019      return new Version (values[0], values[1], values[2], values[3]);
1020    }
1021  }
1022
1023  public class AssemblyResource : IEquatable<AssemblyResource>
1024  {
1025    public AssemblyResource (string fileName, string name)
1026      : this (fileName, name, false)
1027    {
1028    }
1029
1030    public AssemblyResource (string fileName, string name, bool isPrivate)
1031    {
1032      FileName = fileName;
1033      Name = name;
1034      Attributes = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1035    }
1036
1037    public ResourceAttributes Attributes { get; private set; }
1038    public string Name { get; private set; }
1039    public string FileName { get; private set; }
1040    public bool IsEmbeded { get; set; }
1041
1042    #region IEquatable<AssemblyResource> Members
1043
1044    public bool Equals (AssemblyResource other)
1045    {
1046      return Name == other.Name;
1047    }
1048
1049    #endregion
1050  }
1051
1052  //
1053  // A placeholder class for assembly attributes when emitting module
1054  //
1055  class AssemblyAttributesPlaceholder : CompilerGeneratedContainer
1056  {
1057    static readonly string TypeNamePrefix = "<$AssemblyAttributes${0}>";
1058    public static readonly string AssemblyFieldName = "attributes";
1059
1060    Field assembly;
1061
1062    public AssemblyAttributesPlaceholder (ModuleContainer parent, string outputName)
1063      : base (parent, new MemberName (GetGeneratedName (outputName)), Modifiers.STATIC | Modifiers.INTERNAL)
1064    {
1065      assembly = new Field (this, new TypeExpression (parent.Compiler.BuiltinTypes.Object, Location), Modifiers.PUBLIC | Modifiers.STATIC,
1066        new MemberName (AssemblyFieldName), null);
1067
1068      AddField (assembly);
1069    }
1070
1071    public void AddAssemblyAttribute (MethodSpec ctor, byte[] data)
1072    {
1073      assembly.SetCustomAttribute (ctor, data);
1074    }
1075
1076    public static string GetGeneratedName (string outputName)
1077    {
1078      return string.Format (TypeNamePrefix, outputName);
1079    }
1080  }
1081
1082  //
1083  // Extension to System.Reflection.Emit.AssemblyBuilder to have fully compatible
1084  // compiler. This is a default implementation for framework System.Reflection.Emit
1085  // which does not implement any of the methods
1086  //
1087  public class AssemblyBuilderExtension
1088  {
1089    readonly CompilerContext ctx;
1090
1091    public AssemblyBuilderExtension (CompilerContext ctx)
1092    {
1093      this.ctx = ctx;
1094    }
1095
1096    public virtual System.Reflection.Module AddModule (string module)
1097    {
1098      ctx.Report.RuntimeMissingSupport (Location.Null, "-addmodule");
1099      return null;
1100    }
1101
1102    public virtual void AddPermissionRequests (PermissionSet[] permissions)
1103    {
1104      ctx.Report.RuntimeMissingSupport (Location.Null, "assembly declarative security");
1105    }
1106
1107    public virtual void AddTypeForwarder (TypeSpec type, Location loc)
1108    {
1109      ctx.Report.RuntimeMissingSupport (loc, "TypeForwardedToAttribute");
1110    }
1111
1112    public virtual void DefineWin32IconResource (string fileName)
1113    {
1114      ctx.Report.RuntimeMissingSupport (Location.Null, "-win32icon");
1115    }
1116
1117    public virtual void SetAlgorithmId (uint value, Location loc)
1118    {
1119      ctx.Report.RuntimeMissingSupport (loc, "AssemblyAlgorithmIdAttribute");
1120    }
1121
1122    public virtual void SetCulture (string culture, Location loc)
1123    {
1124      ctx.Report.RuntimeMissingSupport (loc, "AssemblyCultureAttribute");
1125    }
1126
1127    public virtual void SetFlags (uint flags, Location loc)
1128    {
1129      ctx.Report.RuntimeMissingSupport (loc, "AssemblyFlagsAttribute");
1130    }
1131
1132    public virtual void SetVersion (Version version, Location loc)
1133    {
1134      ctx.Report.RuntimeMissingSupport (loc, "AssemblyVersionAttribute");
1135    }
1136  }
1137
1138  abstract class AssemblyReferencesLoader<T> where T : class
1139  {
1140    protected readonly CompilerContext compiler;
1141
1142    protected readonly List<string> paths;
1143
1144    protected AssemblyReferencesLoader (CompilerContext compiler)
1145    {
1146      this.compiler = compiler;
1147
1148      paths = new List<string> ();
1149      paths.Add (Directory.GetCurrentDirectory ());
1150      paths.AddRange (compiler.Settings.ReferencesLookupPaths);
1151    }
1152
1153    public abstract bool HasObjectType (T assembly);
1154    protected abstract string[] GetDefaultReferences ();
1155    public abstract T LoadAssemblyFile (string fileName, bool isImplicitReference);
1156    public abstract void LoadReferences (ModuleContainer module);
1157
1158    protected void Error_FileNotFound (string fileName)
1159    {
1160      compiler.Report.Error (6, "Metadata file `{0}' could not be found", fileName);
1161    }
1162
1163    protected void Error_FileCorrupted (string fileName)
1164    {
1165      compiler.Report.Error (9, "Metadata file `{0}' does not contain valid metadata", fileName);
1166    }
1167
1168    protected void Error_AssemblyIsModule (string fileName)
1169    {
1170      compiler.Report.Error (1509,
1171        "Referenced assembly file `{0}' is a module. Consider using `-addmodule' option to add the module",
1172        fileName);
1173    }
1174
1175    protected void Error_ModuleIsAssembly (string fileName)
1176    {
1177      compiler.Report.Error (1542,
1178        "Added module file `{0}' is an assembly. Consider using `-r' option to reference the file",
1179        fileName);
1180    }
1181
1182    protected void LoadReferencesCore (ModuleContainer module, out T corlib_assembly, out List<Tuple<RootNamespace, T>> loaded)
1183    {
1184      compiler.TimeReporter.Start (TimeReporter.TimerType.ReferencesLoading);
1185
1186      loaded = new List<Tuple<RootNamespace, T>> ();
1187
1188      //
1189      // Load mscorlib.dll as the first
1190      //
1191      if (module.Compiler.Settings.StdLib) {
1192        corlib_assembly = LoadAssemblyFile ("mscorlib.dll", true);
1193      } else {
1194        corlib_assembly = default (T);
1195      }
1196
1197      T a;
1198      foreach (string r in module.Compiler.Settings.AssemblyReferences) {
1199        a = LoadAssemblyFile (r, false);
1200        if (a == null || EqualityComparer<T>.Default.Equals (a, corlib_assembly))
1201          continue;
1202
1203        var key = Tuple.Create (module.GlobalRootNamespace, a);
1204        if (loaded.Contains (key))
1205          continue;
1206
1207        loaded.Add (key);
1208      }
1209
1210      if (corlib_assembly == null) {
1211        //
1212        // Requires second pass because HasObjectType can trigger assembly load event
1213        //
1214        for (int i = 0; i < loaded.Count; ++i) {
1215          var assembly = loaded [i];
1216
1217          //
1218          // corlib assembly is the first referenced assembly which contains System.Object
1219          //
1220          if (HasObjectType (assembly.Item2)) {
1221            corlib_assembly = assembly.Item2;
1222            loaded.RemoveAt (i);
1223            break;
1224          }
1225        }
1226      }
1227
1228      foreach (var entry in module.Compiler.Settings.AssemblyReferencesAliases) {
1229        a = LoadAssemblyFile (entry.Item2, false);
1230        if (a == null)
1231          continue;
1232
1233        var key = Tuple.Create (module.CreateRootNamespace (entry.Item1), a);
1234        if (loaded.Contains (key))
1235          continue;
1236
1237        loaded.Add (key);
1238      }
1239
1240      if (compiler.Settings.LoadDefaultReferences) {
1241        foreach (string r in GetDefaultReferences ()) {
1242          a = LoadAssemblyFile (r, true);
1243          if (a == null)
1244            continue;
1245
1246          var key = Tuple.Create (module.GlobalRootNamespace, a);
1247          if (loaded.Contains (key))
1248            continue;
1249
1250          loaded.Add (key);
1251        }
1252      }
1253
1254      compiler.TimeReporter.Stop (TimeReporter.TimerType.ReferencesLoading);
1255    }
1256  }
1257}
Note: See TracBrowser for help on using the repository browser.