This was only for debugging.
[mono.git] / mcs / gmcs / codegen.cs
index 86a9a5bb7db05c35720e60ac7b3c84309b3ffcf2..71f4a9dafdb20f79a84c694bf9496fee576f1104 100755 (executable)
@@ -12,6 +12,10 @@ using System.IO;
 using System.Collections;
 using System.Reflection;
 using System.Reflection.Emit;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+
+using Mono.Security.Cryptography;
 
 namespace Mono.CSharp {
 
@@ -90,15 +94,47 @@ namespace Mono.CSharp {
                //
                static public void Init (string name, string output, bool want_debugging_support)
                {
-                       AssemblyName an;
-
                        FileName = output;
-                       an = new AssemblyName ();
-                       an.Name = Path.GetFileNameWithoutExtension (name);
+                       AssemblyName an = Assembly.GetAssemblyName (name, output);
+
+                       if (an.KeyPair != null) {
+                               // If we are going to strong name our assembly make
+                               // sure all its refs are strong named
+                               foreach (Assembly a in TypeManager.GetAssemblies ()) {
+                                       AssemblyName ref_name = a.GetName ();
+                                       byte [] b = ref_name.GetPublicKeyToken ();
+                                       if (b == null || b.Length == 0) {
+                                               Report.Warning (1577, "Assembly generation failed " +
+                                                               "-- Referenced assembly '" +
+                                                               ref_name.Name +
+                                                               "' does not have a strong name.");
+                                               //Environment.Exit (1);
+                                       }
+                               }
+                       }
                        
                        current_domain = AppDomain.CurrentDomain;
-                       Assembly.Builder = current_domain.DefineDynamicAssembly (
-                               an, AssemblyBuilderAccess.Save, Dirname (name));
+
+                       try {
+                               Assembly.Builder = current_domain.DefineDynamicAssembly (an,
+                                       AssemblyBuilderAccess.Save, Dirname (name));
+                       }
+                       catch (ArgumentException) {
+                               // specified key may not be exportable outside it's container
+                               if (RootContext.StrongNameKeyContainer != null) {
+                                       Report.Error (1548, "Could not access the key inside the container `" +
+                                               RootContext.StrongNameKeyContainer + "'.");
+                                       Environment.Exit (1);
+                               }
+                               throw;
+                       }
+                       catch (CryptographicException) {
+                               if ((RootContext.StrongNameKeyContainer != null) || (RootContext.StrongNameKeyFile != null)) {
+                                       Report.Error (1548, "Could not use the specified key to strongname the assembly.");
+                                       Environment.Exit (1);
+                               }
+                               throw;
+                       }
 
                        //
                        // Pass a path-less name to DefineDynamicModule.  Wonder how
@@ -119,7 +155,17 @@ namespace Mono.CSharp {
                {
                        try {
                                Assembly.Builder.Save (Basename (name));
-                       } catch (System.IO.IOException io){
+                       }
+                       catch (COMException) {
+                               if ((RootContext.StrongNameKeyFile == null) || (!RootContext.StrongNameDelaySign))
+                                       throw;
+
+                               // FIXME: it seems Microsoft AssemblyBuilder doesn't like to delay sign assemblies 
+                               Report.Error (1548, "Couldn't delay-sign the assembly with the '" +
+                                       RootContext.StrongNameKeyFile +
+                                       "', Use MCS with the Mono runtime or CSC to compile this assembly.");
+                       }
+                       catch (System.IO.IOException io) {
                                Report.Error (16, "Could not write to file `"+name+"', cause: " + io.Message);
                        }
                }
@@ -484,6 +530,7 @@ namespace Mono.CSharp {
                                            reachability.IsUnreachable)
                                                unreachable = true;
                                        }
+#if FIXME
                            } catch (Exception e) {
                                        Console.WriteLine ("Exception caught by the compiler while compiling:");
                                        Console.WriteLine ("   Block that caused the problem begin at: " + loc);
@@ -496,6 +543,9 @@ namespace Mono.CSharp {
                                        Console.WriteLine (Report.FriendlyStackTrace (e));
                                        
                                        Environment.Exit (1);
+#else
+                           } finally {
+#endif
                            }
                        }
 
@@ -701,14 +751,17 @@ namespace Mono.CSharp {
                //
                public void EmitThis ()
                {
-                       ig.Emit (OpCodes.Ldarg_0);
-
-                       if (!IsStatic){
-                               if (InIterator)
-                                       ig.Emit (OpCodes.Ldfld, IteratorHandler.Current.this_field);
-                               else
-                                       throw new Exception ("EmitThis for an unknown state");
-                       }
+                       if (InIterator){
+                               ig.Emit (OpCodes.Ldarg_0);
+                               if (!IsStatic){
+                                       FieldBuilder this_field = IteratorHandler.Current.this_field;
+                                       if (TypeManager.IsValueType (this_field.FieldType))
+                                               ig.Emit (OpCodes.Ldflda, this_field);
+                                       else
+                                               ig.Emit (OpCodes.Ldfld, this_field);
+                               } 
+                       } else
+                               ig.Emit (OpCodes.Ldarg_0);
                }
 
                public Expression GetThis (Location loc)
@@ -727,74 +780,221 @@ namespace Mono.CSharp {
        }
 
 
-       public abstract class CommonAssemblyModulClass: IAttributeSupport {
-               Hashtable m_attributes;
+       public abstract class CommonAssemblyModulClass: Attributable {
+               static string[] attribute_targets = new string [] { "assembly", "module" };
 
-               protected CommonAssemblyModulClass () 
+               protected CommonAssemblyModulClass ():
+                       base (null)
                {
-                       m_attributes = new Hashtable ();
                }
 
-               //
-               // Adds a global attribute that was declared in `container', 
-               // the attribute is in `attr', and it was defined at `loc'
-               //                
-               public void AddAttribute (TypeContainer container, AttributeSection attr)
+               public void AddAttributes (ArrayList attrs)
                {
-                       NamespaceEntry ns = container.NamespaceEntry;
-                       Attributes a = (Attributes) m_attributes [ns];
-
-                       if (a == null) {
-                               m_attributes [ns] = new Attributes (attr);
+                       if (OptAttributes == null) {
+                               OptAttributes = new Attributes (attrs);
                                return;
                        }
-
-                       a.AddAttributeSection (attr);
+                       OptAttributes.AddAttributes (attrs);
+                       OptAttributes.CheckTargets (ValidAttributeTargets);
                }
 
-               public virtual void Emit () 
+               public virtual void Emit (TypeContainer tc
                {
-                       if (m_attributes.Count < 1)
+                       if (OptAttributes == null)
                                return;
 
-                       TypeContainer dummy = new TypeContainer ();
-                       EmitContext temp_ec = new EmitContext (dummy, Mono.CSharp.Location.Null, null, null, 0, false);
-                       
-                       foreach (DictionaryEntry de in m_attributes)
-                       {
-                               NamespaceEntry ns = (NamespaceEntry) de.Key;
-                               Attributes attrs = (Attributes) de.Value;
-                               
-                               dummy.NamespaceEntry = ns;
-                               Attribute.ApplyAttributes (temp_ec, null, this, attrs);
+                       EmitContext ec = new EmitContext (tc, Mono.CSharp.Location.Null, null, null, 0, false);
+                       OptAttributes.Emit (ec, this);
+               }
+
+               protected Attribute GetClsCompliantAttribute ()
+               {
+                       if (OptAttributes == null)
+                               return null;
+
+                       EmitContext temp_ec = new EmitContext (new TypeContainer (), Mono.CSharp.Location.Null, null, null, 0, false);
+                       Attribute a = OptAttributes.Search (TypeManager.cls_compliant_attribute_type, temp_ec);
+                       if (a != null) {
+                               a.Resolve (temp_ec);
                        }
+                       return a;
                }
-                
-               #region IAttributeSupport Members
-               public abstract void SetCustomAttribute(CustomAttributeBuilder customBuilder);
-               #endregion
 
+               protected override string[] ValidAttributeTargets {
+                       get {
+                               return attribute_targets;
+                       }
+               }
        }
-       
 
        public class AssemblyClass: CommonAssemblyModulClass {
                // TODO: make it private and move all builder based methods here
                public AssemblyBuilder Builder;
                     
-               bool m_is_cls_compliant;
+               bool is_cls_compliant;
 
                public AssemblyClass (): base ()
                {
-                       m_is_cls_compliant = false;
+                       is_cls_compliant = false;
                }
 
                public bool IsClsCompliant {
                        get {
-                               return m_is_cls_compliant;
+                               return is_cls_compliant;
+                       }
+                       }
+
+               public override AttributeTargets AttributeTargets {
+                       get {
+                               return AttributeTargets.Assembly;
+                       }
+               }
+
+               public override bool IsClsCompliaceRequired(DeclSpace ds)
+               {
+                       return is_cls_compliant;
+               }
+
+               public void ResolveClsCompliance ()
+               {
+                       Attribute a = GetClsCompliantAttribute ();
+                       if (a == null)
+                               return;
+
+                       is_cls_compliant = a.GetClsCompliantAttributeValue (null);
+               }
+
+               public AssemblyName GetAssemblyName (string name, string output) 
+               {
+                       if (OptAttributes != null) {
+                               foreach (Attribute a in OptAttributes.Attrs) {
+                                       if (a.Target != "assembly")
+                                               continue;
+                                       // TODO: This code is buggy: comparing Attribute name without resolving it is wrong.
+                                       //       However, this is invoked by CodeGen.Init, at which time none of the namespaces
+                                       //       are loaded yet.
+                                       switch (a.Name) {
+                                               case "AssemblyKeyFile":
+                                               case "AssemblyKeyFileAttribute":
+                                               case "System.Reflection.AssemblyKeyFileAttribute":
+                                                       if (RootContext.StrongNameKeyFile != null) {
+                                                               Report.Warning (1616, "Compiler option -keyfile overrides " +
+                                                                       "AssemblyKeyFileAttribute");
+                                                       }
+                                                       else {
+                                                               string value = a.GetString ();
+                                                               if (value != String.Empty)
+                                                                       RootContext.StrongNameKeyFile = value;
+                                                       }
+                                                       break;
+                                               case "AssemblyKeyName":
+                                               case "AssemblyKeyNameAttribute":
+                                               case "System.Reflection.AssemblyKeyNameAttribute":
+                                                       if (RootContext.StrongNameKeyContainer != null) {
+                                                               Report.Warning (1616, "Compiler option -keycontainer overrides " +
+                                                                       "AssemblyKeyNameAttribute");
+                                                       }
+                                                       else {
+                                                               string value = a.GetString ();
+                                                               if (value != String.Empty)
+                                                                       RootContext.StrongNameKeyContainer = value;
+                                                       }
+                                                       break;
+                                               case "AssemblyDelaySign":
+                                               case "AssemblyDelaySignAttribute":
+                                               case "System.Reflection.AssemblyDelaySignAttribute":
+                                                       RootContext.StrongNameDelaySign = a.GetBoolean ();
+                                                       break;
+                                       }
+                               }
+                       }
+
+                       AssemblyName an = new AssemblyName ();
+                       an.Name = Path.GetFileNameWithoutExtension (name);
+
+                       // note: delay doesn't apply when using a key container
+                       if (RootContext.StrongNameKeyContainer != null) {
+                               an.KeyPair = new StrongNameKeyPair (RootContext.StrongNameKeyContainer);
+                               return an;
+                       }
+
+                       // strongname is optional
+                       if (RootContext.StrongNameKeyFile == null)
+                               return an;
+
+                       string AssemblyDir = Path.GetDirectoryName (output);
+
+                       // the StrongName key file may be relative to (a) the compiled
+                       // file or (b) to the output assembly. See bugzilla #55320
+                       // http://bugzilla.ximian.com/show_bug.cgi?id=55320
+
+                       // (a) relative to the compiled file
+                       string filename = Path.GetFullPath (RootContext.StrongNameKeyFile);
+                       bool exist = File.Exists (filename);
+                       if ((!exist) && (AssemblyDir != null) && (AssemblyDir != String.Empty)) {
+                               // (b) relative to the outputed assembly
+                               filename = Path.GetFullPath (Path.Combine (AssemblyDir, RootContext.StrongNameKeyFile));
+                               exist = File.Exists (filename);
                        }
+
+                       if (exist) {
+                               using (FileStream fs = new FileStream (filename, FileMode.Open, FileAccess.Read)) {
+                                       byte[] snkeypair = new byte [fs.Length];
+                                       fs.Read (snkeypair, 0, snkeypair.Length);
+
+                                       if (RootContext.StrongNameDelaySign) {
+                                               // delayed signing - DO NOT include private key
+                                               try {
+                                                       // check for possible ECMA key
+                                                       if (snkeypair.Length == 16) {
+                                                               // will be rejected if not "the" ECMA key
+                                                               an.KeyPair = new StrongNameKeyPair (snkeypair);
+                                                       }
+                                                       else {
+                                                               // take it, with or without, a private key
+                                                               RSA rsa = CryptoConvert.FromCapiKeyBlob (snkeypair);
+                                                               // and make sure we only feed the public part to Sys.Ref
+                                                               byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
+                                                               an.KeyPair = new StrongNameKeyPair (publickey);
+                                                       }
+                                               }
+                                               catch (Exception) {
+                                                       Report.Error (1548, "Could not strongname the assembly. File `" +
+                                                               RootContext.StrongNameKeyFile + "' incorrectly encoded.");
+                                                       Environment.Exit (1);
+                                               }
+                                       }
+                                       else {
+                                               // no delay so we make sure we have the private key
+                                               try {
+                                                       CryptoConvert.FromCapiPrivateKeyBlob (snkeypair);
+                                                       an.KeyPair = new StrongNameKeyPair (snkeypair);
+                                               }
+                                               catch (CryptographicException) {
+                                                       if (snkeypair.Length == 16) {
+                                                               // error # is different for ECMA key
+                                                               Report.Error (1606, "Could not strongname the assembly. " + 
+                                                                       "ECMA key can only be used to delay-sign assemblies");
+                                                       }
+                                                       else {
+                                                               Report.Error (1548, "Could not strongname the assembly. File `" +
+                                                                       RootContext.StrongNameKeyFile +
+                                                                       "' doesn't have a private key.");
+                                                       }
+                                                       Environment.Exit (1);
+                                               }
+                                       }
+                               }
+                       }
+                       else {
+                               Report.Error (1548, "Could not strongname the assembly. File `" +
+                                       RootContext.StrongNameKeyFile + "' not found.");
+                               Environment.Exit (1);
+                       }
+                       return an;
                }
 
-               public override void SetCustomAttribute(CustomAttributeBuilder customBuilder)
+               public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
                {
                        Builder.SetCustomAttribute (customBuilder);
                }
@@ -803,7 +1003,6 @@ namespace Mono.CSharp {
        public class ModuleClass: CommonAssemblyModulClass {
                // TODO: make it private and move all builder based methods here
                public ModuleBuilder Builder;
-            
                bool m_module_is_unsafe;
 
                public ModuleClass (bool is_unsafe)
@@ -811,9 +1010,20 @@ namespace Mono.CSharp {
                        m_module_is_unsafe = is_unsafe;
                }
 
-               public override void Emit () 
+               public override AttributeTargets AttributeTargets {
+                       get {
+                               return AttributeTargets.Module;
+                       }
+               }
+
+               public override bool IsClsCompliaceRequired(DeclSpace ds)
                {
-                       base.Emit ();
+                       return CodeGen.Assembly.IsClsCompliant;
+                       }
+
+               public override void Emit (TypeContainer tc) 
+               {
+                       base.Emit (tc);
 
                        if (!m_module_is_unsafe)
                                return;
@@ -823,11 +1033,16 @@ namespace Mono.CSharp {
                                return;
                        }
                                
-                       SetCustomAttribute (new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor, new object [0]));
+                       ApplyAttributeBuilder (null, new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor, new object [0]));
                }
                 
-               public override void SetCustomAttribute(CustomAttributeBuilder customBuilder)
+               public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
                {
+                       if (a != null && a.Type == TypeManager.cls_compliant_attribute_type) {
+                               Report.Warning_T (3012, a.Location);
+                               return;
+                       }
+
                        Builder.SetCustomAttribute (customBuilder);
                }
        }