remove WCF from monotouch
[mcs.git] / mcs / codegen.cs
blobdefe25b92ef420583c62def1043417d94fda6d08
1 //
2 // codegen.cs: The code generator
3 //
4 // Author:
5 // Miguel de Icaza (miguel@ximian.com)
6 //
7 // Copyright 2001, 2002, 2003 Ximian, Inc.
8 // Copyright 2004 Novell, Inc.
9 //
12 // Please leave this defined on SVN: The idea is that when we ship the
13 // compiler to end users, if the compiler crashes, they have a chance
14 // to narrow down the problem.
16 // Only remove it if you need to debug locally on your tree.
18 //#define PRODUCTION
20 using System;
21 using System.IO;
22 using System.Collections;
23 using System.Collections.Specialized;
24 using System.Globalization;
25 using System.Reflection;
26 using System.Reflection.Emit;
27 using System.Runtime.InteropServices;
28 using System.Security;
29 using System.Security.Cryptography;
30 using System.Security.Permissions;
32 using Mono.Security.Cryptography;
34 namespace Mono.CSharp {
36 /// <summary>
37 /// Code generator class.
38 /// </summary>
39 public class CodeGen {
40 static AppDomain current_domain;
42 public static AssemblyClass Assembly;
44 static CodeGen ()
46 Reset ();
49 public static void Reset ()
51 Assembly = new AssemblyClass ();
54 public static string Basename (string name)
56 int pos = name.LastIndexOf ('/');
58 if (pos != -1)
59 return name.Substring (pos + 1);
61 pos = name.LastIndexOf ('\\');
62 if (pos != -1)
63 return name.Substring (pos + 1);
65 return name;
68 public static string Dirname (string name)
70 int pos = name.LastIndexOf ('/');
72 if (pos != -1)
73 return name.Substring (0, pos);
75 pos = name.LastIndexOf ('\\');
76 if (pos != -1)
77 return name.Substring (0, pos);
79 return ".";
82 static public string FileName;
84 #if MS_COMPATIBLE
85 const AssemblyBuilderAccess COMPILER_ACCESS = 0;
86 #else
87 /* Keep this in sync with System.Reflection.Emit.AssemblyBuilder */
88 const AssemblyBuilderAccess COMPILER_ACCESS = (AssemblyBuilderAccess) 0x800;
89 #endif
92 // Initializes the code generator variables for interactive use (repl)
94 static public void InitDynamic (string name)
96 current_domain = AppDomain.CurrentDomain;
97 AssemblyName an = Assembly.GetAssemblyName (name, name);
99 Assembly.Builder = current_domain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Run | COMPILER_ACCESS);
100 RootContext.ToplevelTypes = new ModuleContainer (true);
101 RootContext.ToplevelTypes.Builder = Assembly.Builder.DefineDynamicModule (Basename (name), false);
102 Assembly.Name = Assembly.Builder.GetName ();
106 // Initializes the code generator variables
108 static public bool Init (string name, string output, bool want_debugging_support)
110 FileName = output;
111 AssemblyName an = Assembly.GetAssemblyName (name, output);
112 if (an == null)
113 return false;
115 if (an.KeyPair != null) {
116 // If we are going to strong name our assembly make
117 // sure all its refs are strong named
118 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
119 AssemblyName ref_name = a.GetName ();
120 byte [] b = ref_name.GetPublicKeyToken ();
121 if (b == null || b.Length == 0) {
122 Report.Error (1577, "Assembly generation failed " +
123 "-- Referenced assembly '" +
124 ref_name.Name +
125 "' does not have a strong name.");
126 //Environment.Exit (1);
131 current_domain = AppDomain.CurrentDomain;
133 try {
134 Assembly.Builder = current_domain.DefineDynamicAssembly (an,
135 AssemblyBuilderAccess.RunAndSave | COMPILER_ACCESS, Dirname (name));
137 catch (ArgumentException) {
138 // specified key may not be exportable outside it's container
139 if (RootContext.StrongNameKeyContainer != null) {
140 Report.Error (1548, "Could not access the key inside the container `" +
141 RootContext.StrongNameKeyContainer + "'.");
142 Environment.Exit (1);
144 throw;
146 catch (CryptographicException) {
147 if ((RootContext.StrongNameKeyContainer != null) || (RootContext.StrongNameKeyFile != null)) {
148 Report.Error (1548, "Could not use the specified key to strongname the assembly.");
149 Environment.Exit (1);
151 return false;
154 // Get the complete AssemblyName from the builder
155 // (We need to get the public key and token)
156 Assembly.Name = Assembly.Builder.GetName ();
159 // Pass a path-less name to DefineDynamicModule. Wonder how
160 // this copes with output in different directories then.
161 // FIXME: figure out how this copes with --output /tmp/blah
163 // If the third argument is true, the ModuleBuilder will dynamically
164 // load the default symbol writer.
166 try {
167 RootContext.ToplevelTypes.Builder = Assembly.Builder.DefineDynamicModule (
168 Basename (name), Basename (output), want_debugging_support);
170 #if !MS_COMPATIBLE
171 // TODO: We should use SymbolWriter from DefineDynamicModule
172 if (want_debugging_support && !SymbolWriter.Initialize (RootContext.ToplevelTypes.Builder, output)) {
173 Report.Error (40, "Unexpected debug information initialization error `{0}'",
174 "Could not find the symbol writer assembly (Mono.CompilerServices.SymbolWriter.dll)");
175 return false;
177 #endif
178 } catch (ExecutionEngineException e) {
179 Report.Error (40, "Unexpected debug information initialization error `{0}'",
180 e.Message);
181 return false;
184 return true;
187 static public void Save (string name, bool saveDebugInfo)
189 #if GMCS_SOURCE
190 PortableExecutableKinds pekind;
191 ImageFileMachine machine;
193 switch (RootContext.Platform) {
194 case Platform.X86:
195 pekind = PortableExecutableKinds.Required32Bit;
196 machine = ImageFileMachine.I386;
197 break;
198 case Platform.X64:
199 pekind = PortableExecutableKinds.PE32Plus;
200 machine = ImageFileMachine.AMD64;
201 break;
202 case Platform.IA64:
203 pekind = PortableExecutableKinds.PE32Plus;
204 machine = ImageFileMachine.IA64;
205 break;
206 case Platform.AnyCPU:
207 default:
208 pekind = PortableExecutableKinds.ILOnly;
209 machine = ImageFileMachine.I386;
210 break;
212 #endif
213 try {
214 #if GMCS_SOURCE
215 Assembly.Builder.Save (Basename (name), pekind, machine);
216 #else
217 Assembly.Builder.Save (Basename (name));
218 #endif
220 catch (COMException) {
221 if ((RootContext.StrongNameKeyFile == null) || (!RootContext.StrongNameDelaySign))
222 throw;
224 // FIXME: it seems Microsoft AssemblyBuilder doesn't like to delay sign assemblies
225 Report.Error (1548, "Couldn't delay-sign the assembly with the '" +
226 RootContext.StrongNameKeyFile +
227 "', Use MCS with the Mono runtime or CSC to compile this assembly.");
229 catch (System.IO.IOException io) {
230 Report.Error (16, "Could not write to file `"+name+"', cause: " + io.Message);
231 return;
233 catch (System.UnauthorizedAccessException ua) {
234 Report.Error (16, "Could not write to file `"+name+"', cause: " + ua.Message);
235 return;
237 catch (System.NotImplementedException nie) {
238 Report.RuntimeMissingSupport (Location.Null, nie.Message);
239 return;
243 // Write debuger symbol file
245 if (saveDebugInfo)
246 SymbolWriter.WriteSymbolFile ();
251 /// <summary>
252 /// An Emit Context is created for each body of code (from methods,
253 /// properties bodies, indexer bodies or constructor bodies)
254 /// </summary>
255 public class EmitContext {
257 [Flags]
258 public enum Options
260 /// <summary>
261 /// This flag tracks the `checked' state of the compilation,
262 /// it controls whether we should generate code that does overflow
263 /// checking, or if we generate code that ignores overflows.
265 /// The default setting comes from the command line option to generate
266 /// checked or unchecked code plus any source code changes using the
267 /// checked/unchecked statements or expressions. Contrast this with
268 /// the ConstantCheckState flag.
269 /// </summary>
270 CheckedScope = 1 << 0,
272 /// <summary>
273 /// The constant check state is always set to `true' and cant be changed
274 /// from the command line. The source code can change this setting with
275 /// the `checked' and `unchecked' statements and expressions.
276 /// </summary>
277 ConstantCheckState = 1 << 1,
279 AllCheckStateFlags = CheckedScope | ConstantCheckState,
281 OmitDebugInfo = 1 << 2,
283 ConstructorScope = 1 << 3
286 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
287 // it's public so that we can use a struct at the callsite
288 public struct FlagsHandle : IDisposable
290 EmitContext ec;
291 readonly Options invmask, oldval;
293 public FlagsHandle (EmitContext ec, Options flagsToSet)
294 : this (ec, flagsToSet, flagsToSet)
298 internal FlagsHandle (EmitContext ec, Options mask, Options val)
300 this.ec = ec;
301 invmask = ~mask;
302 oldval = ec.flags & mask;
303 ec.flags = (ec.flags & invmask) | (val & mask);
306 public void Dispose ()
308 ec.flags = (ec.flags & invmask) | oldval;
312 Options flags;
314 public ILGenerator ig;
316 /// <summary>
317 /// The value that is allowed to be returned or NULL if there is no
318 /// return type.
319 /// </summary>
320 protected Type return_type;
322 /// <summary>
323 /// Keeps track of the Type to LocalBuilder temporary storage created
324 /// to store structures (used to compute the address of the structure
325 /// value on structure method invocations)
326 /// </summary>
327 public Hashtable temporary_storage;
329 /// <summary>
330 /// The location where we store the return value.
331 /// </summary>
332 public LocalBuilder return_value;
334 /// <summary>
335 /// The location where return has to jump to return the
336 /// value
337 /// </summary>
338 public Label ReturnLabel;
340 /// <summary>
341 /// If we already defined the ReturnLabel
342 /// </summary>
343 public bool HasReturnLabel;
345 /// <summary>
346 /// Whether we are inside an anonymous method.
347 /// </summary>
348 public AnonymousExpression CurrentAnonymousMethod;
350 public readonly IMemberContext MemberContext;
352 public EmitContext (IMemberContext rc, ILGenerator ig, Type return_type)
354 this.MemberContext = rc;
355 this.ig = ig;
357 this.return_type = return_type;
360 public Type CurrentType {
361 get { return MemberContext.CurrentType; }
364 public TypeParameter[] CurrentTypeParameters {
365 get { return MemberContext.CurrentTypeParameters; }
368 public TypeContainer CurrentTypeDefinition {
369 get { return MemberContext.CurrentTypeDefinition; }
372 public bool HasSet (Options options)
374 return (this.flags & options) == options;
377 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
378 public FlagsHandle With (Options options, bool enable)
380 return new FlagsHandle (this, options, enable ? options : 0);
383 public bool IsStatic {
384 get { return MemberContext.IsStatic; }
387 public Type ReturnType {
388 get {
389 return return_type;
393 /// <summary>
394 /// This is called immediately before emitting an IL opcode to tell the symbol
395 /// writer to which source line this opcode belongs.
396 /// </summary>
397 public void Mark (Location loc)
399 if (!SymbolWriter.HasSymbolWriter || HasSet (Options.OmitDebugInfo) || loc.IsNull)
400 return;
402 SymbolWriter.MarkSequencePoint (ig, loc);
405 public void DefineLocalVariable (string name, LocalBuilder builder)
407 SymbolWriter.DefineLocalVariable (name, builder);
410 public void BeginScope ()
412 ig.BeginScope();
413 SymbolWriter.OpenScope(ig);
416 public void EndScope ()
418 ig.EndScope();
419 SymbolWriter.CloseScope(ig);
422 /// <summary>
423 /// Returns a temporary storage for a variable of type t as
424 /// a local variable in the current body.
425 /// </summary>
426 public LocalBuilder GetTemporaryLocal (Type t)
428 if (temporary_storage != null) {
429 object o = temporary_storage [t];
430 if (o != null) {
431 if (o is Stack) {
432 Stack s = (Stack) o;
433 o = s.Count == 0 ? null : s.Pop ();
434 } else {
435 temporary_storage.Remove (t);
438 if (o != null)
439 return (LocalBuilder) o;
441 return ig.DeclareLocal (t);
444 public void FreeTemporaryLocal (LocalBuilder b, Type t)
446 if (temporary_storage == null) {
447 temporary_storage = new Hashtable ();
448 temporary_storage [t] = b;
449 return;
451 object o = temporary_storage [t];
452 if (o == null) {
453 temporary_storage [t] = b;
454 return;
456 Stack s = o as Stack;
457 if (s == null) {
458 s = new Stack ();
459 s.Push (o);
460 temporary_storage [t] = s;
462 s.Push (b);
465 /// <summary>
466 /// Current loop begin and end labels.
467 /// </summary>
468 public Label LoopBegin, LoopEnd;
470 /// <summary>
471 /// Default target in a switch statement. Only valid if
472 /// InSwitch is true
473 /// </summary>
474 public Label DefaultTarget;
476 /// <summary>
477 /// If this is non-null, points to the current switch statement
478 /// </summary>
479 public Switch Switch;
481 /// <summary>
482 /// ReturnValue creates on demand the LocalBuilder for the
483 /// return value from the function. By default this is not
484 /// used. This is only required when returns are found inside
485 /// Try or Catch statements.
487 /// This method is typically invoked from the Emit phase, so
488 /// we allow the creation of a return label if it was not
489 /// requested during the resolution phase. Could be cleaned
490 /// up, but it would replicate a lot of logic in the Emit phase
491 /// of the code that uses it.
492 /// </summary>
493 public LocalBuilder TemporaryReturn ()
495 if (return_value == null){
496 return_value = ig.DeclareLocal (return_type);
497 if (!HasReturnLabel){
498 ReturnLabel = ig.DefineLabel ();
499 HasReturnLabel = true;
503 return return_value;
507 public abstract class CommonAssemblyModulClass : Attributable, IMemberContext
509 public void AddAttributes (ArrayList attrs, IMemberContext context)
511 foreach (Attribute a in attrs)
512 a.AttachTo (this, context);
514 if (attributes == null) {
515 attributes = new Attributes (attrs);
516 return;
518 attributes.AddAttributes (attrs);
521 public virtual void Emit (TypeContainer tc)
523 if (OptAttributes == null)
524 return;
526 OptAttributes.Emit ();
529 protected Attribute ResolveAttribute (PredefinedAttribute a_type)
531 Attribute a = OptAttributes.Search (a_type);
532 if (a != null) {
533 a.Resolve ();
535 return a;
538 #region IMemberContext Members
540 public Type CurrentType {
541 get { return null; }
544 public TypeParameter[] CurrentTypeParameters {
545 get { return null; }
548 public TypeContainer CurrentTypeDefinition {
549 get { return RootContext.ToplevelTypes; }
552 public string GetSignatureForError ()
554 return "<module>";
557 public bool IsObsolete {
558 get { return false; }
561 public bool IsUnsafe {
562 get { return false; }
565 public bool IsStatic {
566 get { return false; }
569 public ExtensionMethodGroupExpr LookupExtensionMethod (Type extensionType, string name, Location loc)
571 throw new NotImplementedException ();
574 public FullNamedExpression LookupNamespaceOrType (string name, Location loc, bool ignore_cs0104)
576 return RootContext.ToplevelTypes.LookupNamespaceOrType (name, loc, ignore_cs0104);
579 public FullNamedExpression LookupNamespaceAlias (string name)
581 return null;
584 #endregion
587 public class AssemblyClass : CommonAssemblyModulClass {
588 // TODO: make it private and move all builder based methods here
589 public AssemblyBuilder Builder;
590 bool is_cls_compliant;
591 bool wrap_non_exception_throws;
593 public Attribute ClsCompliantAttribute;
595 ListDictionary declarative_security;
596 bool has_extension_method;
597 public AssemblyName Name;
598 MethodInfo add_type_forwarder;
599 ListDictionary emitted_forwarders;
601 // Module is here just because of error messages
602 static string[] attribute_targets = new string [] { "assembly", "module" };
604 public AssemblyClass (): base ()
606 wrap_non_exception_throws = true;
609 public bool HasExtensionMethods {
610 set {
611 has_extension_method = value;
615 public bool IsClsCompliant {
616 get {
617 return is_cls_compliant;
621 public bool WrapNonExceptionThrows {
622 get {
623 return wrap_non_exception_throws;
627 public override AttributeTargets AttributeTargets {
628 get {
629 return AttributeTargets.Assembly;
633 public override bool IsClsComplianceRequired ()
635 return is_cls_compliant;
638 public void Resolve ()
640 if (RootContext.Unsafe) {
642 // Emits [assembly: SecurityPermissionAttribute (SecurityAction.RequestMinimum, SkipVerification = true)]
643 // when -unsafe option was specified
646 Location loc = Location.Null;
648 MemberAccess system_security_permissions = new MemberAccess (new MemberAccess (
649 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Security", loc), "Permissions", loc);
651 Arguments pos = new Arguments (1);
652 pos.Add (new Argument (new MemberAccess (new MemberAccess (system_security_permissions, "SecurityAction", loc), "RequestMinimum")));
654 Arguments named = new Arguments (1);
655 named.Add (new NamedArgument (new LocatedToken (loc, "SkipVerification"), (new BoolLiteral (true, loc))));
657 GlobalAttribute g = new GlobalAttribute (new NamespaceEntry (null, null, null), "assembly",
658 new MemberAccess (system_security_permissions, "SecurityPermissionAttribute"),
659 new Arguments[] { pos, named }, loc, false);
660 g.AttachTo (this, this);
662 if (g.Resolve () != null) {
663 declarative_security = new ListDictionary ();
664 g.ExtractSecurityPermissionSet (declarative_security);
668 if (OptAttributes == null)
669 return;
671 // Ensure that we only have GlobalAttributes, since the Search isn't safe with other types.
672 if (!OptAttributes.CheckTargets())
673 return;
675 ClsCompliantAttribute = ResolveAttribute (PredefinedAttributes.Get.CLSCompliant);
677 if (ClsCompliantAttribute != null) {
678 is_cls_compliant = ClsCompliantAttribute.GetClsCompliantAttributeValue ();
681 Attribute a = ResolveAttribute (PredefinedAttributes.Get.RuntimeCompatibility);
682 if (a != null) {
683 object val = a.GetPropertyValue ("WrapNonExceptionThrows");
684 if (val != null)
685 wrap_non_exception_throws = (bool) val;
689 // fix bug #56621
690 private void SetPublicKey (AssemblyName an, byte[] strongNameBlob)
692 try {
693 // check for possible ECMA key
694 if (strongNameBlob.Length == 16) {
695 // will be rejected if not "the" ECMA key
696 an.SetPublicKey (strongNameBlob);
698 else {
699 // take it, with or without, a private key
700 RSA rsa = CryptoConvert.FromCapiKeyBlob (strongNameBlob);
701 // and make sure we only feed the public part to Sys.Ref
702 byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
704 // AssemblyName.SetPublicKey requires an additional header
705 byte[] publicKeyHeader = new byte [12] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00 };
707 byte[] encodedPublicKey = new byte [12 + publickey.Length];
708 Buffer.BlockCopy (publicKeyHeader, 0, encodedPublicKey, 0, 12);
709 Buffer.BlockCopy (publickey, 0, encodedPublicKey, 12, publickey.Length);
710 an.SetPublicKey (encodedPublicKey);
713 catch (Exception) {
714 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' is incorrectly encoded");
715 Environment.Exit (1);
719 // TODO: rewrite this code (to kill N bugs and make it faster) and use standard ApplyAttribute way.
720 public AssemblyName GetAssemblyName (string name, string output)
722 if (OptAttributes != null) {
723 foreach (Attribute a in OptAttributes.Attrs) {
724 // cannot rely on any resolve-based members before you call Resolve
725 if (a.ExplicitTarget == null || a.ExplicitTarget != "assembly")
726 continue;
728 // TODO: This code is buggy: comparing Attribute name without resolving is wrong.
729 // However, this is invoked by CodeGen.Init, when none of the namespaces
730 // are loaded yet.
731 // TODO: Does not handle quoted attributes properly
732 switch (a.Name) {
733 case "AssemblyKeyFile":
734 case "AssemblyKeyFileAttribute":
735 case "System.Reflection.AssemblyKeyFileAttribute":
736 if (RootContext.StrongNameKeyFile != null) {
737 Report.SymbolRelatedToPreviousError (a.Location, a.GetSignatureForError ());
738 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
739 "keyfile", "System.Reflection.AssemblyKeyFileAttribute");
740 } else {
741 string value = a.GetString ();
742 if (value != null && value.Length != 0)
743 RootContext.StrongNameKeyFile = value;
745 break;
746 case "AssemblyKeyName":
747 case "AssemblyKeyNameAttribute":
748 case "System.Reflection.AssemblyKeyNameAttribute":
749 if (RootContext.StrongNameKeyContainer != null) {
750 Report.SymbolRelatedToPreviousError (a.Location, a.GetSignatureForError ());
751 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
752 "keycontainer", "System.Reflection.AssemblyKeyNameAttribute");
753 } else {
754 string value = a.GetString ();
755 if (value != null && value.Length != 0)
756 RootContext.StrongNameKeyContainer = value;
758 break;
759 case "AssemblyDelaySign":
760 case "AssemblyDelaySignAttribute":
761 case "System.Reflection.AssemblyDelaySignAttribute":
762 RootContext.StrongNameDelaySign = a.GetBoolean ();
763 break;
768 AssemblyName an = new AssemblyName ();
769 an.Name = Path.GetFileNameWithoutExtension (name);
771 // note: delay doesn't apply when using a key container
772 if (RootContext.StrongNameKeyContainer != null) {
773 an.KeyPair = new StrongNameKeyPair (RootContext.StrongNameKeyContainer);
774 return an;
777 // strongname is optional
778 if (RootContext.StrongNameKeyFile == null)
779 return an;
781 string AssemblyDir = Path.GetDirectoryName (output);
783 // the StrongName key file may be relative to (a) the compiled
784 // file or (b) to the output assembly. See bugzilla #55320
785 // http://bugzilla.ximian.com/show_bug.cgi?id=55320
787 // (a) relative to the compiled file
788 string filename = Path.GetFullPath (RootContext.StrongNameKeyFile);
789 bool exist = File.Exists (filename);
790 if ((!exist) && (AssemblyDir != null) && (AssemblyDir != String.Empty)) {
791 // (b) relative to the outputed assembly
792 filename = Path.GetFullPath (Path.Combine (AssemblyDir, RootContext.StrongNameKeyFile));
793 exist = File.Exists (filename);
796 if (exist) {
797 using (FileStream fs = new FileStream (filename, FileMode.Open, FileAccess.Read)) {
798 byte[] snkeypair = new byte [fs.Length];
799 fs.Read (snkeypair, 0, snkeypair.Length);
801 if (RootContext.StrongNameDelaySign) {
802 // delayed signing - DO NOT include private key
803 SetPublicKey (an, snkeypair);
805 else {
806 // no delay so we make sure we have the private key
807 try {
808 CryptoConvert.FromCapiPrivateKeyBlob (snkeypair);
809 an.KeyPair = new StrongNameKeyPair (snkeypair);
811 catch (CryptographicException) {
812 if (snkeypair.Length == 16) {
813 // error # is different for ECMA key
814 Report.Error (1606, "Could not sign the assembly. " +
815 "ECMA key can only be used to delay-sign assemblies");
817 else {
818 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not have a private key");
820 return null;
825 else {
826 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not exist");
827 return null;
829 return an;
832 void Error_AssemblySigning (string text)
834 Report.Error (1548, "Error during assembly signing. " + text);
837 bool CheckInternalsVisibleAttribute (Attribute a)
839 string assembly_name = a.GetString ();
840 if (assembly_name.Length == 0)
841 return false;
843 AssemblyName aname = null;
844 try {
845 #if GMCS_SOURCE
846 aname = new AssemblyName (assembly_name);
847 #else
848 throw new NotSupportedException ();
849 #endif
850 } catch (FileLoadException) {
851 } catch (ArgumentException) {
854 // Bad assembly name format
855 if (aname == null)
856 Report.Warning (1700, 3, a.Location, "Assembly reference `" + assembly_name + "' is invalid and cannot be resolved");
857 // Report error if we have defined Version or Culture
858 else if (aname.Version != null || aname.CultureInfo != null)
859 throw new Exception ("Friend assembly `" + a.GetString () +
860 "' is invalid. InternalsVisibleTo cannot have version or culture specified.");
861 else if (aname.GetPublicKey () == null && Name.GetPublicKey () != null && Name.GetPublicKey ().Length != 0) {
862 Report.Error (1726, a.Location, "Friend assembly reference `" + aname.FullName + "' is invalid." +
863 " Strong named assemblies must specify a public key in their InternalsVisibleTo declarations");
864 return false;
867 return true;
870 static bool IsValidAssemblyVersion (string version)
872 Version v;
873 try {
874 v = new Version (version);
875 } catch {
876 try {
877 int major = int.Parse (version, CultureInfo.InvariantCulture);
878 v = new Version (major, 0);
879 } catch {
880 return false;
884 foreach (int candidate in new int [] { v.Major, v.Minor, v.Build, v.Revision }) {
885 if (candidate > ushort.MaxValue)
886 return false;
889 return true;
892 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa)
894 if (a.IsValidSecurityAttribute ()) {
895 if (declarative_security == null)
896 declarative_security = new ListDictionary ();
898 a.ExtractSecurityPermissionSet (declarative_security);
899 return;
902 if (a.Type == pa.AssemblyCulture) {
903 string value = a.GetString ();
904 if (value == null || value.Length == 0)
905 return;
907 if (RootContext.Target == Target.Exe) {
908 a.Error_AttributeEmitError ("The executables cannot be satelite assemblies, remove the attribute or keep it empty");
909 return;
913 if (a.Type == pa.AssemblyVersion) {
914 string value = a.GetString ();
915 if (value == null || value.Length == 0)
916 return;
918 value = value.Replace ('*', '0');
920 if (!IsValidAssemblyVersion (value)) {
921 a.Error_AttributeEmitError (string.Format ("Specified version `{0}' is not valid", value));
922 return;
926 if (a.Type == pa.InternalsVisibleTo && !CheckInternalsVisibleAttribute (a))
927 return;
929 if (a.Type == pa.TypeForwarder) {
930 Type t = a.GetArgumentType ();
931 if (t == null || TypeManager.HasElementType (t)) {
932 Report.Error (735, a.Location, "Invalid type specified as an argument for TypeForwardedTo attribute");
933 return;
936 t = TypeManager.DropGenericTypeArguments (t);
937 if (emitted_forwarders == null) {
938 emitted_forwarders = new ListDictionary();
939 } else if (emitted_forwarders.Contains(t)) {
940 Report.SymbolRelatedToPreviousError(((Attribute)emitted_forwarders[t]).Location, null);
941 Report.Error(739, a.Location, "A duplicate type forward of type `{0}'",
942 TypeManager.CSharpName(t));
943 return;
946 emitted_forwarders.Add(t, a);
948 if (TypeManager.LookupDeclSpace (t) != null) {
949 Report.SymbolRelatedToPreviousError (t);
950 Report.Error (729, a.Location, "Cannot forward type `{0}' because it is defined in this assembly",
951 TypeManager.CSharpName (t));
952 return;
955 if (t.DeclaringType != null) {
956 Report.Error (730, a.Location, "Cannot forward type `{0}' because it is a nested type",
957 TypeManager.CSharpName (t));
958 return;
961 if (add_type_forwarder == null) {
962 add_type_forwarder = typeof (AssemblyBuilder).GetMethod ("AddTypeForwarder",
963 BindingFlags.NonPublic | BindingFlags.Instance);
965 if (add_type_forwarder == null) {
966 Report.RuntimeMissingSupport (a.Location, "TypeForwardedTo attribute");
967 return;
971 add_type_forwarder.Invoke (Builder, new object[] { t });
972 return;
975 if (a.Type == pa.Extension) {
976 a.Error_MisusedExtensionAttribute ();
977 return;
980 Builder.SetCustomAttribute (cb);
983 public override void Emit (TypeContainer tc)
985 base.Emit (tc);
987 if (has_extension_method)
988 PredefinedAttributes.Get.Extension.EmitAttribute (Builder);
990 // FIXME: Does this belong inside SRE.AssemblyBuilder instead?
991 PredefinedAttribute pa = PredefinedAttributes.Get.RuntimeCompatibility;
992 if (pa.IsDefined && (OptAttributes == null || !OptAttributes.Contains (pa))) {
993 ConstructorInfo ci = TypeManager.GetPredefinedConstructor (
994 pa.Type, Location.Null, Type.EmptyTypes);
995 PropertyInfo [] pis = new PropertyInfo [1];
996 pis [0] = TypeManager.GetPredefinedProperty (pa.Type,
997 "WrapNonExceptionThrows", Location.Null, TypeManager.bool_type);
998 object [] pargs = new object [1];
999 pargs [0] = true;
1000 Builder.SetCustomAttribute (new CustomAttributeBuilder (ci, new object [0], pis, pargs));
1003 if (declarative_security != null) {
1005 MethodInfo add_permission = typeof (AssemblyBuilder).GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1006 object builder_instance = Builder;
1008 try {
1009 // Microsoft runtime hacking
1010 if (add_permission == null) {
1011 Type assembly_builder = typeof (AssemblyBuilder).Assembly.GetType ("System.Reflection.Emit.AssemblyBuilderData");
1012 add_permission = assembly_builder.GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1014 FieldInfo fi = typeof (AssemblyBuilder).GetField ("m_assemblyData", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
1015 builder_instance = fi.GetValue (Builder);
1018 object[] args = new object [] { declarative_security [SecurityAction.RequestMinimum],
1019 declarative_security [SecurityAction.RequestOptional],
1020 declarative_security [SecurityAction.RequestRefuse] };
1021 add_permission.Invoke (builder_instance, args);
1023 catch {
1024 Report.RuntimeMissingSupport (Location.Null, "assembly permission setting");
1029 public override string[] ValidAttributeTargets {
1030 get {
1031 return attribute_targets;
1035 // Wrapper for AssemblyBuilder.AddModule
1036 static MethodInfo adder_method;
1037 static public MethodInfo AddModule_Method {
1038 get {
1039 if (adder_method == null)
1040 adder_method = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.NonPublic);
1041 return adder_method;
1044 public Module AddModule (string module)
1046 MethodInfo m = AddModule_Method;
1047 if (m == null) {
1048 Report.RuntimeMissingSupport (Location.Null, "/addmodule");
1049 Environment.Exit (1);
1052 try {
1053 return (Module) m.Invoke (Builder, new object [] { module });
1054 } catch (TargetInvocationException ex) {
1055 throw ex.InnerException;