Merge pull request #3213 from henricm/fix-for-win-securestring-to-bstr
[mono.git] / mcs / tools / tuner / Mono.Tuner / MoonlightA11yProcessor.cs
1 //
2 // MoonlightA11yProcessor.cs
3 //
4 // Author:
5 //   AndrĂ©s G. Aragoneses (aaragoneses@novell.com)
6 //
7 // (C) 2009 Novell, Inc.
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29
30 using System;
31 using System.Linq;
32
33 using Mono.Cecil;
34
35 using Mono.Linker;
36
37 namespace Mono.Tuner {
38
39         public class MoonlightA11yProcessor : InjectSecurityAttributes {
40
41                 protected override bool ConditionToProcess ()
42                 {
43                         return true;
44                 }
45
46                 protected override void ProcessAssembly (AssemblyDefinition assembly)
47                 {
48                         if (Annotations.GetAction (assembly) != AssemblyAction.Link)
49                                 return;
50
51                         _assembly = assembly;
52
53                         // remove existing [SecurityCritical] and [SecuritySafeCritical]
54                         RemoveSecurityAttributes ();
55
56                         // add [SecurityCritical]
57                         AddSecurityAttributes ();
58
59                         // convert all public members into internal
60                         MakeApiInternal ();
61                 }
62
63                 void MakeApiInternal ()
64                 {
65                         foreach (TypeDefinition type in _assembly.MainModule.Types) {
66                                 if (type.IsPublic)
67                                         type.IsPublic = false;
68
69                                 if (type.HasMethods && !type.Name.EndsWith ("Adapter"))
70                                         foreach (MethodDefinition ctor in type.Methods.Where (m => m.IsConstructor))
71                                                 if (ctor.IsPublic)
72                                                         ctor.IsAssembly = true;
73
74                                 if (type.HasMethods)
75                                         foreach (MethodDefinition method in type.Methods.Where (m => !m.IsConstructor))
76                                                 if (method.IsPublic)
77                                                         method.IsAssembly = true;
78                         }
79                 }
80
81                 void AddSecurityAttributes ()
82                 {
83                         foreach (TypeDefinition type in _assembly.MainModule.Types) {
84                                 AddCriticalAttribute (type);
85
86                                 if (type.HasMethods)
87                                         foreach (MethodDefinition ctor in type.Methods.Where (m => m.IsConstructor))
88                                                 AddCriticalAttribute (ctor);
89
90                                 if (type.HasMethods)
91                                         foreach (MethodDefinition method in type.Methods.Where (m => !m.IsConstructor)) {
92                                                 MethodDefinition parent = null;
93
94                                                 //TODO: take in account generic params
95                                                 if (!method.HasGenericParameters) {
96
97                                                         /*
98                                                          * we need to scan base methods because the CoreCLR complains about SC attribs added
99                                                          * to overriden methods whose base (virtual or interface) method is not marked as SC
100                                                          * with TypeLoadExceptions
101                                                          */
102                                                         parent = GetBaseMethod (type, method);
103                                                 }
104
105                                                 //if there's no base method
106                                                 if (parent == null ||
107
108                                                 //if it's our bridge assembly, we're sure it will (finally, at the end of the linking process) have the SC attrib
109                                                     _assembly.MainModule.Types.Contains (parent.DeclaringType) ||
110
111                                                 //if the type is in the moonlight assemblies, check if it has the SC attrib
112                                                     HasSecurityAttribute (parent, AttributeType.Critical))
113
114                                                         AddCriticalAttribute (method);
115                                 }
116
117                         }
118                 }
119
120                 MethodDefinition GetBaseMethod (TypeDefinition finalType, MethodDefinition final)
121                 {
122                         // both GetOverridenMethod and GetInterfaceMethod return null if there is no base method
123                         return GetOverridenMethod (finalType, final) ?? GetInterfaceMethod (finalType, final);
124                 }
125
126                 //note: will not return abstract methods
127                 MethodDefinition GetOverridenMethod (TypeDefinition finalType, MethodDefinition final)
128                 {
129                         TypeReference baseType = finalType.BaseType;
130                         while (baseType != null && baseType.Resolve () != null) {
131                                 foreach (MethodDefinition method in baseType.Resolve ().Methods) {
132                                         if (!method.IsVirtual || method.Name != final.Name)
133                                                 continue;
134
135                                         //TODO: should we discard them?
136                                         if (method.IsAbstract)
137                                                 continue;
138
139                                         if (HasSameSignature (method, final))
140                                                 return method;
141                                 }
142                                 baseType = baseType.Resolve().BaseType;
143                         }
144                         return null;
145                 }
146
147                 MethodDefinition GetInterfaceMethod (TypeDefinition finalType, MethodDefinition final)
148                 {
149                         TypeDefinition baseType = finalType;
150                         while (baseType != null) {
151                                 if (baseType.HasInterfaces)
152                                         foreach (var @interface in baseType.Interfaces)
153                                                 foreach (MethodDefinition method in @interface.InterfaceType.Resolve ().Methods)
154                                                         if (method.Name == final.Name && HasSameSignature (method, final))
155                                                                 return method;
156
157                                 baseType = baseType.BaseType == null ? null : baseType.BaseType.Resolve ();
158                         }
159                         return null;
160                 }
161
162                 bool HasSameSignature (MethodDefinition method1, MethodDefinition method2)
163                 {
164                         if (method1.ReturnType.FullName != method2.ReturnType.FullName)
165                                 return false;
166
167                         if (method1.Parameters.Count != method2.Parameters.Count)
168                                 return false;
169
170                         for (int i = 0; i < method1.Parameters.Count; i++) {
171                                 if (method1.Parameters [i].ParameterType.FullName !=
172                                     method2.Parameters [i].ParameterType.FullName)
173                                         return false;
174                         }
175
176                         return true;
177                 }
178         }
179 }