2010-03-02 Jb Evain <jbevain@novell.com>
[mono.git] / mcs / tools / linker / Mono.Linker.Steps / SweepStep.cs
1 //
2 // SweepStep.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@gmail.com)
6 //
7 // (C) 2006 Jb Evain
8 // (C) 2007 Novell, Inc.
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 using System.Collections;
31
32 using Mono.Cecil;
33
34 namespace Mono.Linker.Steps {
35
36         public class SweepStep : IStep {
37
38                 AssemblyDefinition [] assemblies;
39
40                 public void Process (LinkContext context)
41                 {
42                         assemblies = context.GetAssemblies ();
43                         foreach (var assembly in assemblies)
44                                 SweepAssembly (assembly);
45                 }
46
47                 void SweepAssembly (AssemblyDefinition assembly)
48                 {
49                         if (Annotations.GetAction (assembly) != AssemblyAction.Link)
50                                 return;
51
52                         if (!IsMarkedAssembly (assembly)) {
53                                 RemoveAssembly (assembly);
54                                 return;
55                         }
56
57                         var types = assembly.MainModule.Types;
58                         var cloned_types = Clone (types);
59
60                         types.Clear ();
61
62                         foreach (TypeDefinition type in cloned_types) {
63                                 if (Annotations.IsMarked (type)) {
64                                         SweepType (type);
65                                         types.Add (type);
66                                         continue;
67                                 }
68
69                                 SweepReferences (assembly, type);
70                         }
71                 }
72
73                 static bool IsMarkedAssembly (AssemblyDefinition assembly)
74                 {
75                         return Annotations.IsMarked (assembly.MainModule);
76                 }
77
78                 void RemoveAssembly (AssemblyDefinition assembly)
79                 {
80                         Annotations.SetAction (assembly, AssemblyAction.Delete);
81
82                         SweepReferences (assembly);
83                 }
84
85                 void SweepReferences (AssemblyDefinition target)
86                 {
87                         foreach (var assembly in assemblies)
88                                 SweepReferences (assembly, target);
89                 }
90
91                 void SweepReferences (AssemblyDefinition assembly, AssemblyDefinition target)
92                 {
93                         var references = assembly.MainModule.AssemblyReferences;
94                         for (int i = 0; i < references.Count; i++) {
95                                 var reference = references [i];
96                                 if (!AreSameReference (reference, target.Name))
97                                         continue;
98
99                                 references.RemoveAt (i);
100                                 return;
101                         }
102                 }
103
104                 static ICollection Clone (ICollection collection)
105                 {
106                         return new ArrayList (collection);
107                 }
108
109                 void SweepReferences (AssemblyDefinition assembly, TypeDefinition type)
110                 {
111                         foreach (AssemblyDefinition asm in assemblies) {
112                                 ModuleDefinition module = asm.MainModule;
113                                 if (!module.TypeReferences.Contains (type))
114                                         continue;
115
116                                 TypeReference typeRef = module.TypeReferences [type.FullName];
117                                 if (AssemblyMatch (assembly, typeRef)) {
118                                         SweepMemberReferences (module, typeRef);
119                                         module.TypeReferences.Remove (typeRef);
120                                 }
121                         }
122                 }
123
124                 static void SweepMemberReferences (ModuleDefinition module, TypeReference reference)
125                 {
126                         var references = module.MemberReferences;
127
128                         for (int i = 0; i < references.Count; i++) {
129                                 if (references [i].DeclaringType == reference)
130                                         references.RemoveAt (i--);
131                         }
132                 }
133
134                 static bool AssemblyMatch (AssemblyDefinition assembly, TypeReference type)
135                 {
136                         AssemblyNameReference reference = type.Scope as AssemblyNameReference;
137                         if (reference == null)
138                                 return false;
139
140                         return AreSameReference (assembly.Name, reference);
141                 }
142
143                 static void SweepType (TypeDefinition type)
144                 {
145                         if (type.HasFields)
146                                 SweepCollection (type.Fields);
147
148                         if (type.HasConstructors)
149                                 SweepCollection (type.Constructors);
150
151                         if (type.HasMethods)
152                                 SweepCollection (type.Methods);
153                 }
154
155                 static void SweepCollection (IList list)
156                 {
157                         for (int i = 0; i < list.Count; i++)
158                                 if (!Annotations.IsMarked ((IAnnotationProvider) list [i]))
159                                         list.RemoveAt (i--);
160                 }
161
162                 static bool AreSameReference (AssemblyNameReference a, AssemblyNameReference b)
163                 {
164                         if (a == b)
165                                 return true;
166
167                         if (a.Name != b.Name)
168                                 return false;
169
170                         if (a.Version != b.Version)
171                                 return false;
172
173                         return true;
174                 }
175         }
176 }