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 if (Annotations.GetAction (assembly) != AssemblyAction.Link)
50 Report ("in assembly {0}", assembly.Name);
52 foreach (ModuleDefinition module in assembly.Modules)
53 foreach (TypeDefinition type in module.Types)
57 void CheckType (TypeDefinition type)
59 if (!IsVisibleFrom (type, type.BaseType)) {
60 Report ("Base type `{0}` of type `{1}` is not visible",
64 CheckInterfaces (type);
67 CheckConstructors (type);
71 void CheckInterfaces (TypeDefinition type)
73 foreach (TypeReference iface in type.Interfaces) {
74 if (!IsVisibleFrom (type, iface)) {
75 Report ("Interface `{0}` implemented by `{1}` is not visible",
81 static bool IsPublic (TypeDefinition type)
83 return (type.DeclaringType == null && type.IsPublic) || type.IsNestedPublic;
86 static bool AreInDifferentAssemblies (TypeDefinition lhs, TypeDefinition rhs)
88 return lhs.Module.Assembly.Name.FullName != rhs.Module.Assembly.Name.FullName;
91 bool IsVisibleFrom (TypeDefinition type, TypeReference reference)
93 if (reference == null)
96 if (reference is GenericParameter || reference.GetOriginalType () is GenericParameter)
99 TypeDefinition other = Context.Resolver.Resolve (reference);
103 if (!AreInDifferentAssemblies (type, other))
106 if (IsPublic (other))
112 bool IsVisibleFrom (TypeDefinition type, MethodReference reference)
114 if (reference == null)
117 MethodDefinition meth = null;
119 meth = Context.Resolver.Resolve (reference);
120 } catch (ResolutionException) {}
125 TypeDefinition dec = (TypeDefinition) meth.DeclaringType;
126 if (!IsVisibleFrom (type, dec))
132 if (type == dec || type.DeclaringType == dec)
135 if (meth.IsFamily && InHierarchy (type, dec))
138 if (meth.IsFamilyOrAssembly && (!AreInDifferentAssemblies (type, dec) || InHierarchy (type, dec)))
141 if (!AreInDifferentAssemblies (type, dec) && meth.IsAssembly)
147 bool IsVisibleFrom (TypeDefinition type, FieldReference reference)
149 if (reference == null)
152 FieldDefinition field = null;
154 field = Context.Resolver.Resolve (reference);
155 } catch (ResolutionException) {}
160 TypeDefinition dec = (TypeDefinition) field.DeclaringType;
161 if (!IsVisibleFrom (type, dec))
167 if (type == dec || type.DeclaringType == dec)
170 if (field.IsFamily && InHierarchy (type, dec))
173 if (field.IsFamilyOrAssembly && (!AreInDifferentAssemblies (type, dec) || InHierarchy (type, dec)))
176 if (!AreInDifferentAssemblies (type, dec) && field.IsAssembly)
182 bool InHierarchy (TypeDefinition type, TypeDefinition other)
184 if (type.BaseType == null)
187 TypeDefinition baseType = Context.Resolver.Resolve (type.BaseType);
189 if (baseType == other)
192 return InHierarchy (baseType, other);
195 static void Report (string pattern, params object [] parameters)
197 Console.WriteLine ("[check] " + pattern, parameters);
200 void CheckFields (TypeDefinition type)
202 foreach (FieldDefinition field in type.Fields) {
203 if (!IsVisibleFrom (type, field.FieldType)) {
204 Report ("Field `{0}` of type `{1}` is not visible from `{2}`",
205 field.Name, field.FieldType, type);
210 void CheckConstructors (TypeDefinition type)
212 CheckMethods (type, type.Constructors);
215 void CheckMethods (TypeDefinition type)
217 CheckMethods (type, type.Methods);
220 void CheckMethods (TypeDefinition type, ICollection methods)
222 foreach (MethodDefinition method in methods) {
223 if (!IsVisibleFrom (type, method.ReturnType.ReturnType)) {
224 Report ("Method return type `{0}` in method `{1}` is not visible",
225 method.ReturnType.ReturnType, method);
228 foreach (ParameterDefinition parameter in method.Parameters) {
229 if (!IsVisibleFrom (type, parameter.ParameterType)) {
230 Report ("Parameter `{0}` of type `{1}` in method `{2}` is not visible.",
231 parameter.Sequence, parameter.ParameterType, method);
240 void CheckBody (MethodDefinition method)
242 TypeDefinition type = (TypeDefinition) method.DeclaringType;
244 foreach (VariableDefinition variable in method.Body.Variables) {
245 if (!IsVisibleFrom ((TypeDefinition) method.DeclaringType, variable.VariableType)) {
246 Report ("Variable `{0}` of type `{1}` from method `{2}` is not visible",
247 variable.Index, variable.VariableType, method);
251 foreach (Instruction instr in method.Body.Instructions) {
252 switch (instr.OpCode.OperandType) {
253 case OperandType.InlineType:
254 case OperandType.InlineMethod:
255 case OperandType.InlineField:
256 case OperandType.InlineTok:
258 TypeReference type_ref = instr.Operand as TypeReference;
259 if (type_ref != null)
260 error = !IsVisibleFrom (type, type_ref);
262 MethodReference meth_ref = instr.Operand as MethodReference;
263 if (meth_ref != null)
264 error = !IsVisibleFrom (type, meth_ref);
266 FieldReference field_ref = instr.Operand as FieldReference;
267 if (field_ref != null)
268 error = !IsVisibleFrom (type, field_ref);
271 Report ("Operand `{0}` of type {1} at offset 0x{2} in method `{3}` is not visible",
272 instr.Operand, instr.OpCode.OperandType, instr.Offset.ToString ("x4"), method);