@@ -49,8 +49,54 @@ public static void Analyze(INameService service, ICollection<ModuleDefMD> module
4949 return ;
5050
5151 var vTbl = service . GetVTables ( ) [ method . DeclaringType ] ;
52- VTableSignature sig = VTableSignature . FromMethod ( method ) ;
53- var slots = vTbl . FindSlots ( method ) ;
52+ var slots = vTbl . FindSlots ( method ) . ToArray ( ) ;
53+
54+ IMemberDef discoveredBaseMemberDef = null ;
55+ MethodDef discoveredBaseMethodDef = null ;
56+
57+ bool doesOverridePropertyOrEvent = false ;
58+ var methodProp = method . DeclaringType . Properties . Where ( p => BelongsToProperty ( p , method ) ) ;
59+ foreach ( var prop in methodProp ) {
60+ foreach ( var baseMethodDef in FindBaseDeclarations ( service , method ) ) {
61+ var basePropDef = baseMethodDef . DeclaringType . Properties .
62+ FirstOrDefault ( p => BelongsToProperty ( p , baseMethodDef ) && String . Equals ( p . Name , prop . Name , StringComparison . Ordinal ) ) ;
63+
64+ if ( basePropDef is null ) continue ;
65+
66+ // Name of property has to line up.
67+ CreateOverrideReference ( service , prop , basePropDef ) ;
68+ CreateSiblingReference ( basePropDef , ref discoveredBaseMemberDef , service ) ;
69+
70+ // Method names have to line up as well (otherwise inheriting attributes does not work).
71+ CreateOverrideReference ( service , method , baseMethodDef ) ;
72+ CreateSiblingReference ( baseMethodDef , ref discoveredBaseMethodDef , service ) ;
73+
74+ doesOverridePropertyOrEvent = true ;
75+ }
76+ }
77+
78+ discoveredBaseMemberDef = null ;
79+ discoveredBaseMethodDef = null ;
80+
81+ var methodEvent = method . DeclaringType . Events . Where ( e => BelongsToEvent ( e , method ) ) ;
82+ foreach ( var evt in methodEvent ) {
83+ foreach ( var baseMethodDef in FindBaseDeclarations ( service , method ) ) {
84+ var baseEventDef = baseMethodDef . DeclaringType . Events .
85+ FirstOrDefault ( e => BelongsToEvent ( e , baseMethodDef ) && String . Equals ( e . Name , evt . Name , StringComparison . Ordinal ) ) ;
86+
87+ if ( baseEventDef is null ) continue ;
88+
89+ // Name of event has to line up.
90+ CreateOverrideReference ( service , evt , baseEventDef ) ;
91+ CreateSiblingReference ( baseEventDef , ref discoveredBaseMemberDef , service ) ;
92+
93+ // Method names have to line up as well (otherwise inheriting attributes does not work).
94+ CreateOverrideReference ( service , method , baseMethodDef ) ;
95+ CreateSiblingReference ( baseMethodDef , ref discoveredBaseMethodDef , service ) ;
96+
97+ doesOverridePropertyOrEvent = true ;
98+ }
99+ }
54100
55101 if ( ! method . IsAbstract ) {
56102 foreach ( var slot in slots ) {
@@ -60,17 +106,117 @@ public static void Analyze(INameService service, ICollection<ModuleDefMD> module
60106 SetupOverwriteReferences ( service , modules , slot , method . Module ) ;
61107 }
62108 }
109+ else if ( ! doesOverridePropertyOrEvent ) {
110+ foreach ( var baseMethodDef in FindBaseDeclarations ( service , method ) ) {
111+ CreateOverrideReference ( service , method , baseMethodDef ) ;
112+ }
113+ }
114+ }
115+
116+ static void CreateSiblingReference < T > ( T basePropDef , ref T discoveredBaseMemberDef , INameService service ) where T : class , IMemberDef {
117+ if ( discoveredBaseMemberDef is null )
118+ discoveredBaseMemberDef = basePropDef ;
119+ else {
120+ var references = service . GetReferences ( discoveredBaseMemberDef ) . OfType < MemberSiblingReference > ( ) . ToArray ( ) ;
121+ if ( references . Length > 0 ) {
122+ discoveredBaseMemberDef = ( T ) references [ 0 ] . OldestSiblingDef ;
123+ foreach ( var siblingRef in references . Skip ( 1 ) ) {
124+ // Redirect all the siblings to the new oldest reference
125+ RedirectSiblingReferences ( siblingRef . OldestSiblingDef , discoveredBaseMemberDef , service ) ;
126+ }
127+ }
128+
129+ service . AddReference ( basePropDef , new MemberSiblingReference ( basePropDef , discoveredBaseMemberDef ) ) ;
130+ UpdateOldestSiblingReference ( discoveredBaseMemberDef , basePropDef , service ) ;
131+ }
132+ }
133+
134+ static void UpdateOldestSiblingReference ( IMemberDef oldestSiblingMemberDef , IMemberDef basePropDef , INameService service ) {
135+ var reverseReference = service . GetReferences ( oldestSiblingMemberDef ) . OfType < MemberOldestSiblingReference > ( )
136+ . SingleOrDefault ( ) ;
137+ if ( reverseReference is null ) {
138+ service . AddReference ( oldestSiblingMemberDef , new MemberOldestSiblingReference ( oldestSiblingMemberDef , basePropDef ) ) ;
139+ PropagateRenamingRestrictions ( service , oldestSiblingMemberDef , basePropDef ) ;
140+ }
141+ else if ( ! reverseReference . OtherSiblings . Contains ( basePropDef ) ) {
142+ reverseReference . OtherSiblings . Add ( basePropDef ) ;
143+ PropagateRenamingRestrictions ( service , reverseReference . OtherSiblings ) ;
144+ }
145+ }
146+
147+ static void RedirectSiblingReferences ( IMemberDef oldMemberDef , IMemberDef newMemberDef , INameService service ) {
148+ if ( ReferenceEquals ( oldMemberDef , newMemberDef ) ) return ;
149+
150+ var referencesToUpdate = service . GetReferences ( oldMemberDef )
151+ . OfType < MemberOldestSiblingReference > ( )
152+ . SelectMany ( r => r . OtherSiblings )
153+ . SelectMany ( service . GetReferences )
154+ . OfType < MemberSiblingReference > ( )
155+ . Where ( r => ReferenceEquals ( r . OldestSiblingDef , oldMemberDef ) ) ;
156+
157+ foreach ( var reference in referencesToUpdate ) {
158+ reference . OldestSiblingDef = newMemberDef ;
159+ UpdateOldestSiblingReference ( newMemberDef , reference . ThisMemberDef , service ) ;
160+ }
161+ UpdateOldestSiblingReference ( newMemberDef , oldMemberDef , service ) ;
162+ }
163+
164+ static void CreateOverrideReference ( INameService service , IMemberDef thisMemberDef , IMemberDef baseMemberDef ) {
165+ var overrideRef = new MemberOverrideReference ( thisMemberDef , baseMemberDef ) ;
166+ service . AddReference ( thisMemberDef , overrideRef ) ;
167+
168+ PropagateRenamingRestrictions ( service , thisMemberDef , baseMemberDef ) ;
169+ }
170+
171+ static void PropagateRenamingRestrictions ( INameService service , params object [ ] objects ) =>
172+ PropagateRenamingRestrictions ( service , ( IList < object > ) objects ) ;
173+
174+ static void PropagateRenamingRestrictions ( INameService service , IList < object > objects ) {
175+ if ( ! objects . All ( service . CanRename ) ) {
176+ foreach ( var o in objects ) {
177+ service . SetCanRename ( o , false ) ;
178+ }
179+ }
63180 else {
181+ var minimalRenamingLevel = objects . Max ( service . GetRenameMode ) ;
182+ foreach ( var o in objects ) {
183+ service . ReduceRenameMode ( o , minimalRenamingLevel ) ;
184+ }
185+ }
186+ }
187+
188+ private static IEnumerable < MethodDef > FindBaseDeclarations ( INameService service , MethodDef method ) {
189+ var unprocessed = new Queue < MethodDef > ( ) ;
190+ unprocessed . Enqueue ( method ) ;
191+
192+ var vTables = service . GetVTables ( ) ;
193+
194+ while ( unprocessed . Any ( ) ) {
195+ var currentMethod = unprocessed . Dequeue ( ) ;
196+
197+ var vTbl = vTables [ currentMethod . DeclaringType ] ;
198+ var slots = vTbl . FindSlots ( currentMethod ) . Where ( s => s . Overrides != null ) ;
199+
200+ bool slotsExists = false ;
64201 foreach ( var slot in slots ) {
65- if ( slot . Overrides == null )
66- continue ;
67- service . SetCanRename ( method , false ) ;
68- service . SetCanRename ( slot . Overrides . MethodDef , false ) ;
202+ unprocessed . Enqueue ( slot . Overrides . MethodDef ) ;
203+ slotsExists = true ;
69204 }
205+
206+ if ( ! slotsExists && method != currentMethod )
207+ yield return currentMethod ;
70208 }
71209 }
72210
73- private static void AddImportReference ( INameService service , ICollection < ModuleDefMD > modules , ModuleDef module , MethodDef method , MemberRef methodRef ) {
211+ private static bool BelongsToProperty ( PropertyDef propertyDef , MethodDef methodDef ) =>
212+ propertyDef . GetMethods . Contains ( methodDef ) || propertyDef . SetMethods . Contains ( methodDef ) ||
213+ ( propertyDef . HasOtherMethods && propertyDef . OtherMethods . Contains ( methodDef ) ) ;
214+
215+ private static bool BelongsToEvent ( EventDef eventDef , MethodDef methodDef ) =>
216+ Equals ( eventDef . AddMethod , methodDef ) || Equals ( eventDef . RemoveMethod , methodDef ) || Equals ( eventDef . InvokeMethod , methodDef ) ||
217+ ( eventDef . HasOtherMethods && eventDef . OtherMethods . Contains ( methodDef ) ) ;
218+
219+ private static void AddImportReference ( INameService service , ICollection < ModuleDefMD > modules , ModuleDef module , MethodDef method , MemberRef methodRef ) {
74220 if ( method . Module != module && modules . Contains ( ( ModuleDefMD ) module ) ) {
75221 var declType = ( TypeRef ) methodRef . DeclaringType . ScopeType ;
76222 service . AddReference ( method . DeclaringType , new TypeRefReference ( declType , method . DeclaringType ) ) ;
@@ -88,8 +234,8 @@ private static void AddImportReference(INameService service, ICollection<ModuleD
88234 private static void SetupTypeReference ( INameService service , ICollection < ModuleDefMD > modules , ModuleDef module , ITypeDefOrRef typeDefOrRef ) {
89235 if ( ! ( typeDefOrRef is TypeRef typeRef ) ) return ;
90236
91- var def = typeRef . ResolveTypeDefThrow ( ) ;
92- if ( def . Module != module && modules . Contains ( ( ModuleDefMD ) def . Module ) )
237+ var def = typeRef . ResolveTypeDef ( ) ;
238+ if ( ! ( def is null ) && def . Module != module && modules . Contains ( ( ModuleDefMD ) def . Module ) )
93239 service . AddReference ( def , new TypeRefReference ( typeRef , def ) ) ;
94240 }
95241
@@ -99,7 +245,7 @@ private static GenericInstSig SetupSignatureReferences(INameService service, ICo
99245 return new GenericInstSig ( genericType , genericArguments ) ;
100246 }
101247
102- private static T SetupSignatureReferences < T > ( INameService service , ICollection < ModuleDefMD > modules , ModuleDef module , T typeSig ) where T : TypeSig {
248+ private static T SetupSignatureReferences < T > ( INameService service , ICollection < ModuleDefMD > modules , ModuleDef module , T typeSig ) where T : TypeSig {
103249 var asTypeRef = typeSig . TryGetTypeRef ( ) ;
104250 if ( asTypeRef != null ) {
105251 SetupTypeReference ( service , modules , module , asTypeRef ) ;
@@ -172,22 +318,8 @@ public void PostRename(ConfuserContext context, INameService service, Protection
172318 if ( method == null || ! method . IsVirtual || method . Overrides . Count == 0 )
173319 return ;
174320
175- var methods = new HashSet < IMethodDefOrRef > ( MethodDefOrRefComparer . Instance ) ;
176321 method . Overrides
177- . RemoveWhere ( impl => MethodDefOrRefComparer . Instance . Equals ( impl . MethodDeclaration , method ) ) ;
178- }
179-
180- class MethodDefOrRefComparer : IEqualityComparer < IMethodDefOrRef > {
181- public static readonly MethodDefOrRefComparer Instance = new MethodDefOrRefComparer ( ) ;
182- MethodDefOrRefComparer ( ) { }
183-
184- public bool Equals ( IMethodDefOrRef x , IMethodDefOrRef y ) {
185- return new SigComparer ( ) . Equals ( x , y ) && new SigComparer ( ) . Equals ( x . DeclaringType , y . DeclaringType ) ;
186- }
187-
188- public int GetHashCode ( IMethodDefOrRef obj ) {
189- return new SigComparer ( ) . GetHashCode ( obj ) * 5 + new SigComparer ( ) . GetHashCode ( obj . DeclaringType ) ;
190- }
322+ . RemoveWhere ( impl => MethodEqualityComparer . CompareDeclaringTypes . Equals ( impl . MethodDeclaration , method ) ) ;
191323 }
192324 }
193325}
0 commit comments