5 // Jb Evain (jbevain@novell.com)
7 // (C) 2007 Novell, Inc.
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
30 using System.Collections;
33 using Mono.Linker.Steps;
38 namespace Mono.Tuner {
40 public class CheckVisibility : BaseStep {
42 protected override void ProcessAssembly (AssemblyDefinition assembly)
44 if (assembly.Name.Name == "mscorlib" || assembly.Name.Name == "smcs")
47 Report ("in assembly {0}", assembly.Name);
49 foreach (ModuleDefinition module in assembly.Modules)
50 foreach (TypeDefinition type in module.Types)
54 void CheckType (TypeDefinition type)
56 if (!IsVisibleFrom (type, type.BaseType)) {
57 Report ("Base type `{0}` of type `{1}` is not visible",
61 CheckInterfaces (type);
64 CheckConstructors (type);
68 void CheckInterfaces (TypeDefinition type)
70 foreach (TypeReference iface in type.Interfaces) {
71 if (!IsVisibleFrom (type, iface)) {
72 Report ("Interface `{0}` implemented by `{1}` is not visible",
78 static bool IsPublic (TypeDefinition type)
80 return (type.DeclaringType == null && type.IsPublic) || type.IsNestedPublic;
83 static bool AreInDifferentAssemblies (TypeDefinition lhs, TypeDefinition rhs)
85 return lhs.Module.Assembly.Name.FullName != rhs.Module.Assembly.Name.FullName;
88 bool IsVisibleFrom (TypeDefinition type, TypeReference reference)
90 if (reference == null)
93 if (reference is GenericParameter || reference.GetOriginalType () is GenericParameter)
96 TypeDefinition other = Context.Resolver.Resolve (reference);
100 if (!AreInDifferentAssemblies (type, other))
103 if (IsPublic (other))
109 bool IsVisibleFrom (TypeDefinition type, MethodReference reference)
111 if (reference == null)
114 MethodDefinition meth = null;
116 meth = Context.Resolver.Resolve (reference);
117 } catch (ResolutionException) {}
122 TypeDefinition dec = (TypeDefinition) meth.DeclaringType;
123 if (!IsVisibleFrom (type, dec))
129 if (type == dec || type.DeclaringType == dec)
132 if (meth.IsFamily && InHierarchy (type, dec))
135 if (!AreInDifferentAssemblies (type, dec) && meth.IsAssembly)
141 bool IsVisibleFrom (TypeDefinition type, FieldReference reference)
143 if (reference == null)
146 FieldDefinition field = null;
148 field = Context.Resolver.Resolve (reference);
149 } catch (ResolutionException) {}
154 TypeDefinition dec = (TypeDefinition) field.DeclaringType;
155 if (!IsVisibleFrom (type, dec))
161 if (type == dec || type.DeclaringType == dec)
164 if (field.IsFamily && InHierarchy (type, dec))
167 if (!AreInDifferentAssemblies (type, dec) && field.IsAssembly)
173 bool InHierarchy (TypeDefinition type, TypeDefinition other)
175 if (type.BaseType == null)
178 TypeDefinition baseType = Context.Resolver.Resolve (type.BaseType);
180 if (baseType == other)
183 return InHierarchy (baseType, other);
186 static void Report (string pattern, params object [] parameters)
188 Console.WriteLine ("[check] " + pattern, parameters);
191 void CheckFields (TypeDefinition type)
193 foreach (FieldDefinition field in type.Fields) {
194 if (!IsVisibleFrom (type, field.FieldType)) {
195 Report ("Field `{0}` of type `{1}` is not visible from `{2}`",
196 field.Name, field.FieldType, type);
201 void CheckConstructors (TypeDefinition type)
203 CheckMethods (type, type.Constructors);
206 void CheckMethods (TypeDefinition type)
208 CheckMethods (type, type.Methods);
211 void CheckMethods (TypeDefinition type, ICollection methods)
213 foreach (MethodDefinition method in methods) {
214 if (!IsVisibleFrom (type, method.ReturnType.ReturnType)) {
215 Report ("Method return type `{0}` in method `{1}` is not visible",
216 method.ReturnType.ReturnType, method);
219 foreach (ParameterDefinition parameter in method.Parameters) {
220 if (!IsVisibleFrom (type, parameter.ParameterType)) {
221 Report ("Parameter `{0}` of type `{1}` in method `{2}` is not visible.",
222 parameter.Sequence, parameter.ParameterType, method);
231 void CheckBody (MethodDefinition method)
233 TypeDefinition type = (TypeDefinition) method.DeclaringType;
235 foreach (VariableDefinition variable in method.Body.Variables) {
236 if (!IsVisibleFrom ((TypeDefinition) method.DeclaringType, variable.VariableType)) {
237 Report ("Variable `{0}` of type `{1}` from method `{2}` is not visible",
238 variable.Index, variable.VariableType, method);
242 foreach (Instruction instr in method.Body.Instructions) {
243 switch (instr.OpCode.OperandType) {
244 case OperandType.InlineType:
245 case OperandType.InlineMethod:
246 case OperandType.InlineField:
247 case OperandType.InlineTok:
249 TypeReference type_ref = instr.Operand as TypeReference;
250 if (type_ref != null)
251 error = !IsVisibleFrom (type, type_ref);
253 MethodReference meth_ref = instr.Operand as MethodReference;
254 if (meth_ref != null)
255 error = !IsVisibleFrom (type, meth_ref);
257 FieldReference field_ref = instr.Operand as FieldReference;
258 if (field_ref != null)
259 error = !IsVisibleFrom (type, field_ref);
262 Report ("Operand `{0}` of type {1} at offset 0x{2} in method `{3}` is not visible",
263 instr.Operand, instr.OpCode.OperandType, instr.Offset.ToString ("x4"), method);