5 // Jb Evain (jbevain@gmail.com)
8 // (C) 2007 Novell, Inc.
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
30 using System
.Collections
;
31 using System
.Collections
.Generic
;
33 using Mono
.Collections
.Generic
;
35 namespace Mono
.Linker
.Steps
{
37 public class SweepStep
: BaseStep
{
39 AssemblyDefinition
[] assemblies
;
40 HashSet
<AssemblyDefinition
> resolvedTypeReferences
;
42 protected override void Process ()
44 assemblies
= Context
.GetAssemblies ();
45 foreach (var assembly
in assemblies
) {
46 SweepAssembly (assembly
);
47 if (Annotations
.GetAction (assembly
) == AssemblyAction
.Copy
) {
48 // Copy assemblies can still contain Type references with
49 // type forwarders from Delete assemblies
50 // thus try to resolve all the type references and see
51 // if some changed the scope. if yes change the action to Save
52 if (ResolveAllTypeReferences (assembly
))
53 Annotations
.SetAction (assembly
, AssemblyAction
.Save
);
58 void SweepAssembly (AssemblyDefinition assembly
)
60 if (Annotations
.GetAction (assembly
) != AssemblyAction
.Link
)
63 if (!IsMarkedAssembly (assembly
)) {
64 RemoveAssembly (assembly
);
68 var types
= new List
<TypeDefinition
> ();
70 foreach (TypeDefinition type
in assembly
.MainModule
.Types
) {
71 if (Annotations
.IsMarked (type
)) {
77 if (type
.Name
== "<Module>")
81 assembly
.MainModule
.Types
.Clear ();
82 foreach (TypeDefinition type
in types
)
83 assembly
.MainModule
.Types
.Add (type
);
86 bool IsMarkedAssembly (AssemblyDefinition assembly
)
88 return Annotations
.IsMarked (assembly
.MainModule
);
91 void RemoveAssembly (AssemblyDefinition assembly
)
93 Annotations
.SetAction (assembly
, AssemblyAction
.Delete
);
95 SweepReferences (assembly
);
98 void SweepReferences (AssemblyDefinition target
)
100 foreach (var assembly
in assemblies
)
101 SweepReferences (assembly
, target
);
104 void SweepReferences (AssemblyDefinition assembly
, AssemblyDefinition target
)
106 if (assembly
== target
)
109 var references
= assembly
.MainModule
.AssemblyReferences
;
110 for (int i
= 0; i
< references
.Count
; i
++) {
111 var reference
= references
[i
];
112 var r
= Context
.Resolver
.Resolve (reference
);
113 if (!AreSameReference (r
.Name
, target
.Name
))
116 references
.RemoveAt (i
);
117 // Removing the reference does not mean it will be saved back to disk!
118 // That depends on the AssemblyAction set for the `assembly`
119 switch (Annotations
.GetAction (assembly
)) {
120 case AssemblyAction
.Copy
:
121 // Copy means even if "unlinked" we still want that assembly to be saved back
122 // to disk (OutputStep) without the (removed) reference
123 Annotations
.SetAction (assembly
, AssemblyAction
.Save
);
124 ResolveAllTypeReferences (assembly
);
127 case AssemblyAction
.Save
:
128 case AssemblyAction
.Link
:
129 ResolveAllTypeReferences (assembly
);
136 bool ResolveAllTypeReferences (AssemblyDefinition assembly
)
138 if (resolvedTypeReferences
== null)
139 resolvedTypeReferences
= new HashSet
<AssemblyDefinition
> ();
140 if (resolvedTypeReferences
.Contains (assembly
))
142 resolvedTypeReferences
.Add (assembly
);
144 var hash
= new Dictionary
<TypeReference
,IMetadataScope
> ();
145 bool changes
= false;
147 foreach (TypeReference tr
in assembly
.MainModule
.GetTypeReferences ()) {
148 if (hash
.ContainsKey (tr
))
150 var td
= tr
.Resolve ();
151 IMetadataScope scope
= tr
.Scope
;
152 // at this stage reference might include things that can't be resolved
153 // and if it is (resolved) it needs to be kept only if marked (#16213)
154 if ((td
!= null) && Annotations
.IsMarked (td
)) {
155 scope
= assembly
.MainModule
.ImportReference (td
).Scope
;
156 if (tr
.Scope
!= scope
)
158 hash
.Add (tr
, scope
);
161 if (assembly
.MainModule
.HasExportedTypes
) {
162 foreach (var et
in assembly
.MainModule
.ExportedTypes
) {
163 var td
= et
.Resolve ();
164 IMetadataScope scope
= et
.Scope
;
165 if ((td
!= null) && Annotations
.IsMarked (td
)) {
166 scope
= assembly
.MainModule
.ImportReference (td
).Scope
;
167 hash
.Add (td
, scope
);
172 // Resolve everything first before updating scopes.
173 // If we set the scope to null, then calling Resolve() on any of its
174 // nested types would crash.
176 foreach (var e
in hash
) {
177 e
.Key
.Scope
= e
.Value
;
183 void SweepType (TypeDefinition type
)
186 SweepCollection (type
.Fields
);
189 SweepCollection (type
.Methods
);
191 if (type
.HasNestedTypes
)
192 SweepNestedTypes (type
);
195 void SweepNestedTypes (TypeDefinition type
)
197 for (int i
= 0; i
< type
.NestedTypes
.Count
; i
++) {
198 var nested
= type
.NestedTypes
[i
];
199 if (Annotations
.IsMarked (nested
)) {
202 type
.NestedTypes
.RemoveAt (i
--);
207 void SweepCollection (IList list
)
209 for (int i
= 0; i
< list
.Count
; i
++)
210 if (!Annotations
.IsMarked ((IMetadataTokenProvider
) list
[i
]))
214 static bool AreSameReference (AssemblyNameReference a
, AssemblyNameReference b
)
219 if (a
.Name
!= b
.Name
)
222 if (a
.Version
> b
.Version
)