-
Notifications
You must be signed in to change notification settings - Fork 5.2k
[ILLink] Add interface implementing type to OverrideInformation and use where it makes sense #98274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
8454427
Refactor OverrideInformation to include interface implementing type
jtschuster 54c326d
Add NotNullWhenAttribute for InterfaceImplementor
jtschuster 6bfc58a
Don't allow null interfaceImpl when base and override are interface m…
jtschuster ecc5d0c
Add InterfaceType to InterfaceImplementor
jtschuster 310de30
Make new members internal for compat warnings
jtschuster 77195a3
Make InterfaceImplementor internal for API compat
jtschuster a73cc1f
Make TypeMapInfo internal for API Compat
jtschuster 76bc255
Add InterfaceImplementor to suppressions.xml
jtschuster 11577fa
Make types public again
jtschuster 5fb3256
Use correct InterfaceImplementor in FindAndAddDims
jtschuster 3b4a69d
InterfaceImplementor doesn't need to directly implement the interface
jtschuster 14814ed
PR Feedback
jtschuster 56f23e4
Don't need to resolve TypeDefinitions
jtschuster ccd0a8f
Merge branch 'main' of https://github.com/dotnet/runtime into CheckIm…
jtschuster 1d1e883
Use correct InterfaceImpl
jtschuster 7b218b6
Add argument to first call
jtschuster 9addd27
Merge branch 'main' of https://github.com/dotnet/runtime into CheckIm…
jtschuster 81ebc93
Look on base types and interfaces for interfaceImpl
jtschuster 2110159
Add test case and invert if
jtschuster 488ff72
PR feedback:
jtschuster File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
src/tools/illink/src/linker/Linker/InterfaceImplementor.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| // Copyright (c) .NET Foundation and contributors. All rights reserved. | ||
| // Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
|
||
| using System; | ||
| using System.Collections; | ||
| using System.Collections.Generic; | ||
| using System.Diagnostics; | ||
| using Mono.Cecil; | ||
|
|
||
| namespace Mono.Linker | ||
| { | ||
| public class InterfaceImplementor | ||
| { | ||
| /// <summary> | ||
| /// The type that implements <see cref="InterfaceImplementor.InterfaceType"/>. | ||
| /// </summary> | ||
| public TypeDefinition Implementor { get; } | ||
| /// <summary> | ||
| /// The .interfaceimpl on <see cref="InterfaceImplementor.Implementor"/>that points to <see cref="InterfaceImplementor.InterfaceType"/> | ||
| /// </summary> | ||
| public InterfaceImplementation InterfaceImplementation { get; } | ||
| /// <summary> | ||
| /// The type of the interface that is implemented by <see cref="InterfaceImplementor.Implementor"/> | ||
| /// </summary> | ||
| public TypeDefinition InterfaceType { get; } | ||
jtschuster marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| public InterfaceImplementor (TypeDefinition implementor, InterfaceImplementation interfaceImplementation, TypeDefinition interfaceType, IMetadataResolver resolver) | ||
| { | ||
| Implementor = implementor; | ||
| InterfaceImplementation = interfaceImplementation; | ||
| InterfaceType = interfaceType; | ||
| Debug.Assert(resolver.Resolve (interfaceImplementation.InterfaceType) == interfaceType); | ||
| } | ||
|
|
||
| public static InterfaceImplementor Create(TypeDefinition implementor, TypeDefinition interfaceType, IMetadataResolver resolver) | ||
| { | ||
| foreach(InterfaceImplementation iface in implementor.Interfaces) { | ||
| if (resolver.Resolve(iface.InterfaceType) == interfaceType) { | ||
| return new InterfaceImplementor(implementor, iface, interfaceType, resolver); | ||
| } | ||
| } | ||
|
|
||
| Queue<TypeDefinition> ifacesToCheck = new (); | ||
| ifacesToCheck.Enqueue(implementor); | ||
| while (ifacesToCheck.Count > 0) { | ||
| var currentIface = ifacesToCheck.Dequeue (); | ||
|
|
||
| foreach(InterfaceImplementation ifaceImpl in currentIface.Interfaces) { | ||
| var iface = resolver.Resolve (ifaceImpl.InterfaceType); | ||
| if (iface == interfaceType) { | ||
| return new InterfaceImplementor(implementor, ifaceImpl, interfaceType, resolver); | ||
| } | ||
| ifacesToCheck.Enqueue (iface); | ||
| } | ||
| } | ||
| throw new InvalidOperationException ($"Type '{implementor.FullName}' does not implement interface '{interfaceType.FullName}' directly or through any interfaces"); | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,71 +3,39 @@ | |
|
|
||
| using System.Diagnostics; | ||
| using Mono.Cecil; | ||
| using System.Diagnostics.CodeAnalysis; | ||
|
|
||
| namespace Mono.Linker | ||
| { | ||
| [DebuggerDisplay ("{Override}")] | ||
| public class OverrideInformation | ||
| { | ||
| readonly ITryResolveMetadata resolver; | ||
| readonly OverridePair _pair; | ||
| private InterfaceImplementation? _matchingInterfaceImplementation; | ||
| public MethodDefinition Base { get; } | ||
|
|
||
| public OverrideInformation (MethodDefinition @base, MethodDefinition @override, ITryResolveMetadata resolver, InterfaceImplementation? matchingInterfaceImplementation = null) | ||
| { | ||
| _pair = new OverridePair (@base, @override); | ||
| _matchingInterfaceImplementation = matchingInterfaceImplementation; | ||
| this.resolver = resolver; | ||
| } | ||
| public readonly record struct OverridePair (MethodDefinition Base, MethodDefinition Override) | ||
| { | ||
| public bool IsStaticInterfaceMethodPair () => Base.DeclaringType.IsInterface && Base.IsStatic && Override.IsStatic; | ||
| public InterfaceImplementation? GetMatchingInterfaceImplementation (ITryResolveMetadata resolver) | ||
| { | ||
| if (!Base.DeclaringType.IsInterface) | ||
| return null; | ||
| var interfaceType = Base.DeclaringType; | ||
| foreach (var @interface in Override.DeclaringType.Interfaces) { | ||
| if (resolver.TryResolve (@interface.InterfaceType)?.Equals (interfaceType) == true) { | ||
| return @interface; | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
| } | ||
| public MethodDefinition Override { get; } | ||
|
|
||
| public MethodDefinition Base { get => _pair.Base; } | ||
| public MethodDefinition Override { get => _pair.Override; } | ||
| public InterfaceImplementation? MatchingInterfaceImplementation { | ||
| get { | ||
| if (_matchingInterfaceImplementation is not null) | ||
| return _matchingInterfaceImplementation; | ||
| _matchingInterfaceImplementation = _pair.GetMatchingInterfaceImplementation (resolver); | ||
| return _matchingInterfaceImplementation; | ||
| } | ||
| } | ||
| internal InterfaceImplementor? InterfaceImplementor { get; } | ||
|
|
||
| public bool IsOverrideOfInterfaceMember { | ||
| get { | ||
| if (MatchingInterfaceImplementation != null) | ||
| return true; | ||
|
|
||
| return Base.DeclaringType.IsInterface; | ||
| } | ||
| internal OverrideInformation (MethodDefinition @base, MethodDefinition @override, InterfaceImplementor? interfaceImplementor = null) | ||
| { | ||
| Base = @base; | ||
| Override = @override; | ||
| InterfaceImplementor = interfaceImplementor; | ||
| // Ensure we have an interface implementation if the base method is from an interface and the override method is on a class | ||
| Debug.Assert(@base.DeclaringType.IsInterface && interfaceImplementor != null | ||
jtschuster marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| || [email protected] && interfaceImplementor == null); | ||
| // Ensure the interfaceImplementor is for the interface we expect | ||
| Debug.Assert (@base.DeclaringType.IsInterface ? interfaceImplementor!.InterfaceType == @base.DeclaringType : true); | ||
| } | ||
|
|
||
| public TypeDefinition? InterfaceType { | ||
| get { | ||
| if (!IsOverrideOfInterfaceMember) | ||
| return null; | ||
| public InterfaceImplementation? MatchingInterfaceImplementation | ||
| => InterfaceImplementor?.InterfaceImplementation; | ||
|
|
||
| if (MatchingInterfaceImplementation != null) | ||
| return resolver.TryResolve (MatchingInterfaceImplementation.InterfaceType); | ||
|
|
||
| return Base.DeclaringType; | ||
| } | ||
| } | ||
| public TypeDefinition? InterfaceType | ||
| => InterfaceImplementor?.InterfaceType; | ||
|
|
||
| public bool IsStaticInterfaceMethodPair => _pair.IsStaticInterfaceMethodPair (); | ||
| [MemberNotNullWhen (true, nameof (InterfaceImplementor), nameof (MatchingInterfaceImplementation))] | ||
| public bool IsOverrideOfInterfaceMember | ||
| => InterfaceImplementor != null; | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.