[w32handle] Stop returning 0 in every cases for locking/unlocking (#3926)
[mono.git] / mcs / tools / tuner / Mono.Tuner / CheckVisibility.cs
index 757be40b1491f299e791bf23fe7b692ee37b30d1..df553db5abe7470398c3518866735a875abd8bc3 100644 (file)
@@ -28,6 +28,7 @@
 
 using System;
 using System.Collections;
+using System.Text;
 
 using Mono.Linker;
 using Mono.Linker.Steps;
@@ -39,6 +40,22 @@ namespace Mono.Tuner {
 
        public class CheckVisibility : BaseStep {
 
+               bool throw_on_error;
+
+               protected override void Process ()
+               {
+                       throw_on_error = GetThrowOnVisibilityErrorParameter ();
+               }
+
+               bool GetThrowOnVisibilityErrorParameter ()
+               {
+                       try {
+                               return bool.Parse (Context.GetParameter ("throw_on_visibility_error"));
+                       } catch {
+                               return false;
+                       }
+               }
+
                protected override void ProcessAssembly (AssemblyDefinition assembly)
                {
                        if (assembly.Name.Name == "mscorlib" || assembly.Name.Name == "smcs")
@@ -57,22 +74,21 @@ namespace Mono.Tuner {
                void CheckType (TypeDefinition type)
                {
                        if (!IsVisibleFrom (type, type.BaseType)) {
-                               Report ("Base type `{0}` of type `{1}` is not visible",
+                               ReportError ("Base type `{0}` of type `{1}` is not visible",
                                        type.BaseType, type);
                        }
 
                        CheckInterfaces (type);
 
                        CheckFields (type);
-                       CheckConstructors (type);
                        CheckMethods (type);
                }
 
                void CheckInterfaces (TypeDefinition type)
                {
-                       foreach (TypeReference iface in type.Interfaces) {
-                               if (!IsVisibleFrom (type, iface)) {
-                                       Report ("Interface `{0}` implemented by `{1}` is not visible",
+                       foreach (var iface in type.Interfaces) {
+                               if (!IsVisibleFrom (type, iface.InterfaceType)) {
+                                       ReportError ("Interface `{0}` implemented by `{1}` is not visible",
                                                iface, type);
                                }
                        }
@@ -83,9 +99,61 @@ namespace Mono.Tuner {
                        return (type.DeclaringType == null && type.IsPublic) || type.IsNestedPublic;
                }
 
-               static bool AreInDifferentAssemblies (TypeDefinition lhs, TypeDefinition rhs)
+               static bool AreInDifferentAssemblies (TypeDefinition type, TypeDefinition target)
                {
-                       return lhs.Module.Assembly.Name.FullName != rhs.Module.Assembly.Name.FullName;
+                       if (type.Module.Assembly.Name.FullName == target.Module.Assembly.Name.FullName)
+                               return false;
+
+                       return !IsInternalVisibleTo (target.Module.Assembly, type.Module.Assembly);
+               }
+
+               static bool IsInternalVisibleTo (AssemblyDefinition assembly, AssemblyDefinition candidate)
+               {
+                       foreach (CustomAttribute attribute in assembly.CustomAttributes) {
+                               if (!IsInternalsVisibleToAttribute (attribute))
+                                       continue;
+
+                               if (attribute.ConstructorArguments.Count == 0)
+                                       continue;
+
+                               string signature = (string) attribute.ConstructorArguments [0].Value;
+
+                               if (InternalsVisibleToSignatureMatch (signature, candidate.Name))
+                                       return true;
+                       }
+
+                       return false;
+               }
+
+               static bool InternalsVisibleToSignatureMatch (string signature, AssemblyNameReference reference)
+               {
+                       int pos = signature.IndexOf (",");
+                       if (pos == -1)
+                               return signature == reference.Name;
+
+                       string assembly_name = signature.Substring (0, pos);
+
+                       pos = signature.IndexOf ("=");
+                       if (pos == -1)
+                               throw new ArgumentException ();
+
+                       string public_key = signature.Substring (pos + 1).ToLower ();
+
+                       return assembly_name == reference.Name && public_key == ToPublicKeyString (reference.PublicKey);
+               }
+
+               static string ToPublicKeyString (byte [] public_key)
+               {
+                       StringBuilder signature = new StringBuilder (public_key.Length);
+                       for (int i = 0; i < public_key.Length; i++)
+                               signature.Append (public_key [i].ToString ("x2"));
+
+                       return signature.ToString ();
+               }
+
+               static bool IsInternalsVisibleToAttribute (CustomAttribute attribute)
+               {
+                       return attribute.Constructor.DeclaringType.FullName == "System.Runtime.CompilerServices.InternalsVisibleToAttribute";
                }
 
                bool IsVisibleFrom (TypeDefinition type, TypeReference reference)
@@ -93,7 +161,7 @@ namespace Mono.Tuner {
                        if (reference == null)
                                return true;
 
-                       if (reference is GenericParameter || reference.GetOriginalType () is GenericParameter)
+                       if (reference is GenericParameter || reference.GetElementType () is GenericParameter)
                                return true;
 
                        TypeDefinition other = reference.Resolve ();
@@ -125,7 +193,7 @@ namespace Mono.Tuner {
                        if (meth.IsPublic)
                                return true;
 
-                       if (type == dec || type.DeclaringType == dec)
+                       if (type == dec || IsNestedIn (type, dec))
                                return true;
 
                        if (meth.IsFamily && InHierarchy (type, dec))
@@ -159,7 +227,7 @@ namespace Mono.Tuner {
                        if (field.IsPublic)
                                return true;
 
-                       if (type == dec || type.DeclaringType == dec)
+                       if (type == dec || IsNestedIn (type, dec))
                                return true;
 
                        if (field.IsFamily && InHierarchy (type, dec))
@@ -177,7 +245,23 @@ namespace Mono.Tuner {
                        return false;
                }
 
-               bool InHierarchy (TypeDefinition type, TypeDefinition other)
+               static bool IsNestedIn (TypeDefinition type, TypeDefinition other)
+               {
+                       TypeDefinition declaring = type.DeclaringType;
+
+                       if (declaring == null)
+                               return false;
+
+                       if (declaring == other)
+                               return true;
+
+                       if (declaring.DeclaringType == null)
+                               return false;
+
+                       return IsNestedIn (declaring, other);
+               }
+
+               static bool InHierarchy (TypeDefinition type, TypeDefinition other)
                {
                        if (type.BaseType == null)
                                return false;
@@ -195,21 +279,24 @@ namespace Mono.Tuner {
                        Console.WriteLine ("[check] " + pattern, parameters);
                }
 
+               void ReportError (string pattern, params object [] parameters)
+               {
+                       Report (pattern, parameters);
+
+                       if (throw_on_error)
+                               throw new VisibilityErrorException (string.Format (pattern, parameters));
+               }
+
                void CheckFields (TypeDefinition type)
                {
                        foreach (FieldDefinition field in type.Fields) {
                                if (!IsVisibleFrom (type, field.FieldType)) {
-                                       Report ("Field `{0}` of type `{1}` is not visible from `{2}`",
+                                       ReportError ("Field `{0}` of type `{1}` is not visible from `{2}`",
                                                field.Name, field.FieldType, type);
                                }
                        }
                }
 
-               void CheckConstructors (TypeDefinition type)
-               {
-                       CheckMethods (type, type.Constructors);
-               }
-
                void CheckMethods (TypeDefinition type)
                {
                        CheckMethods (type, type.Methods);
@@ -218,15 +305,15 @@ namespace Mono.Tuner {
                void CheckMethods (TypeDefinition type, ICollection methods)
                {
                        foreach (MethodDefinition method in methods) {
-                               if (!IsVisibleFrom (type, method.ReturnType.ReturnType)) {
-                                       Report ("Method return type `{0}` in method `{1}` is not visible",
-                                               method.ReturnType.ReturnType, method);
+                               if (!IsVisibleFrom (type, method.ReturnType)) {
+                                       ReportError ("Method return type `{0}` in method `{1}` is not visible",
+                                               method.ReturnType, method);
                                }
 
                                foreach (ParameterDefinition parameter in method.Parameters) {
                                        if (!IsVisibleFrom (type, parameter.ParameterType)) {
-                                               Report ("Parameter `{0}` of type `{1}` in method `{2}` is not visible.",
-                                                       parameter.Sequence, parameter.ParameterType, method);
+                                               ReportError ("Parameter `{0}` of type `{1}` in method `{2}` is not visible.",
+                                                       parameter.Index, parameter.ParameterType, method);
                                        }
                                }
 
@@ -241,7 +328,7 @@ namespace Mono.Tuner {
 
                        foreach (VariableDefinition variable in method.Body.Variables) {
                                if (!IsVisibleFrom ((TypeDefinition) method.DeclaringType, variable.VariableType)) {
-                                       Report ("Variable `{0}` of type `{1}` from method `{2}` is not visible",
+                                       ReportError ("Variable `{0}` of type `{1}` from method `{2}` is not visible",
                                                variable.Index, variable.VariableType, method);
                                }
                        }
@@ -266,7 +353,7 @@ namespace Mono.Tuner {
                                                error = !IsVisibleFrom (type, field_ref);
 
                                        if (error) {
-                                               Report ("Operand `{0}` of type {1} at offset 0x{2} in method `{3}` is not visible",
+                                               ReportError ("Operand `{0}` of type {1} at offset 0x{2} in method `{3}` is not visible",
                                                        instr.Operand, instr.OpCode.OperandType, instr.Offset.ToString ("x4"), method);
                                        }
 
@@ -276,5 +363,13 @@ namespace Mono.Tuner {
                                }
                        }
                }
+
+               class VisibilityErrorException : Exception {
+
+                       public VisibilityErrorException (string message)
+                               : base (message)
+                       {
+                       }
+               }
        }
 }