PageRenderTime 67ms CodeModel.GetById 21ms app.highlight 36ms RepoModel.GetById 1ms app.codeStats 1ms

/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/assembly.cs

http://github.com/icsharpcode/ILSpy
C# | 1257 lines | 949 code | 205 blank | 103 comment | 272 complexity | c382a7c8436f5f93110a050cd81d264a MD5 | raw file
   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}