@@ -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,98 @@ 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 ;
63119 else {
64- foreach ( var slot in slots ) {
65- if ( slot . Overrides == null )
66- continue ;
67- service . SetCanRename ( method , false ) ;
68- service . SetCanRename ( slot . Overrides . MethodDef , false ) ;
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+ else if ( ! reverseReference . OtherSiblings . Contains ( basePropDef ) ) {
140+ reverseReference . OtherSiblings . Add ( basePropDef ) ;
141+ }
142+ }
143+
144+ static void RedirectSiblingReferences ( IMemberDef oldMemberDef , IMemberDef newMemberDef , INameService service ) {
145+ if ( ReferenceEquals ( oldMemberDef , newMemberDef ) ) return ;
146+
147+ var referencesToUpdate = service . GetReferences ( oldMemberDef )
148+ . OfType < MemberOldestSiblingReference > ( )
149+ . SelectMany ( r => r . OtherSiblings )
150+ . SelectMany ( service . GetReferences )
151+ . OfType < MemberSiblingReference > ( )
152+ . Where ( r => ReferenceEquals ( r . OldestSiblingDef , oldMemberDef ) ) ;
153+
154+ foreach ( var reference in referencesToUpdate ) {
155+ reference . OldestSiblingDef = newMemberDef ;
156+ UpdateOldestSiblingReference ( newMemberDef , reference . ThisMemberDef , service ) ;
157+ }
158+ UpdateOldestSiblingReference ( newMemberDef , oldMemberDef , service ) ;
159+ }
160+
161+ static void CreateOverrideReference ( INameService service , IMemberDef thisMemberDef , IMemberDef baseMemberDef ) {
162+ var overrideRef = new MemberOverrideReference ( thisMemberDef , baseMemberDef ) ;
163+ service . AddReference ( thisMemberDef , overrideRef ) ;
164+
165+ if ( ! service . CanRename ( thisMemberDef ) )
166+ service . SetCanRename ( baseMemberDef , false ) ;
167+ }
168+
169+
170+ private static IEnumerable < MethodDef > FindBaseDeclarations ( INameService service , MethodDef method ) {
171+ var unprocessed = new Queue < MethodDef > ( ) ;
172+ unprocessed . Enqueue ( method ) ;
173+
174+ var vTables = service . GetVTables ( ) ;
175+
176+ while ( unprocessed . Any ( ) ) {
177+ var currentMethod = unprocessed . Dequeue ( ) ;
178+
179+ var vTbl = vTables [ currentMethod . DeclaringType ] ;
180+ var slots = vTbl . FindSlots ( currentMethod ) . Where ( s => s . Overrides != null ) . ToArray ( ) ;
181+ if ( slots . Any ( ) ) {
182+ foreach ( var slot in slots ) {
183+ unprocessed . Enqueue ( slot . Overrides . MethodDef ) ;
184+ }
185+ }
186+ else if ( method != currentMethod ) {
187+ yield return currentMethod ;
69188 }
70189 }
71190 }
72191
73- private static void AddImportReference ( INameService service , ICollection < ModuleDefMD > modules , ModuleDef module , MethodDef method , MemberRef methodRef ) {
192+ private static bool BelongsToProperty ( PropertyDef propertyDef , MethodDef methodDef ) =>
193+ propertyDef . GetMethods . Contains ( methodDef ) || propertyDef . SetMethods . Contains ( methodDef ) ||
194+ ( propertyDef . HasOtherMethods && propertyDef . OtherMethods . Contains ( methodDef ) ) ;
195+
196+ private static bool BelongsToEvent ( EventDef eventDef , MethodDef methodDef ) =>
197+ Equals ( eventDef . AddMethod , methodDef ) || Equals ( eventDef . RemoveMethod , methodDef ) || Equals ( eventDef . InvokeMethod , methodDef ) ||
198+ ( eventDef . HasOtherMethods && eventDef . OtherMethods . Contains ( methodDef ) ) ;
199+
200+ private static void AddImportReference ( INameService service , ICollection < ModuleDefMD > modules , ModuleDef module , MethodDef method , MemberRef methodRef ) {
74201 if ( method . Module != module && modules . Contains ( ( ModuleDefMD ) module ) ) {
75202 var declType = ( TypeRef ) methodRef . DeclaringType . ScopeType ;
76203 service . AddReference ( method . DeclaringType , new TypeRefReference ( declType , method . DeclaringType ) ) ;
@@ -88,8 +215,8 @@ private static void AddImportReference(INameService service, ICollection<ModuleD
88215 private static void SetupTypeReference ( INameService service , ICollection < ModuleDefMD > modules , ModuleDef module , ITypeDefOrRef typeDefOrRef ) {
89216 if ( ! ( typeDefOrRef is TypeRef typeRef ) ) return ;
90217
91- var def = typeRef . ResolveTypeDefThrow ( ) ;
92- if ( def . Module != module && modules . Contains ( ( ModuleDefMD ) def . Module ) )
218+ var def = typeRef . ResolveTypeDef ( ) ;
219+ if ( ! ( def is null ) && def . Module != module && modules . Contains ( ( ModuleDefMD ) def . Module ) )
93220 service . AddReference ( def , new TypeRefReference ( typeRef , def ) ) ;
94221 }
95222
@@ -99,7 +226,7 @@ private static GenericInstSig SetupSignatureReferences(INameService service, ICo
99226 return new GenericInstSig ( genericType , genericArguments ) ;
100227 }
101228
102- private static T SetupSignatureReferences < T > ( INameService service , ICollection < ModuleDefMD > modules , ModuleDef module , T typeSig ) where T : TypeSig {
229+ private static T SetupSignatureReferences < T > ( INameService service , ICollection < ModuleDefMD > modules , ModuleDef module , T typeSig ) where T : TypeSig {
103230 var asTypeRef = typeSig . TryGetTypeRef ( ) ;
104231 if ( asTypeRef != null ) {
105232 SetupTypeReference ( service , modules , module , asTypeRef ) ;
0 commit comments