Skip to content
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

Interface inheritance follow up #85117

Merged
merged 36 commits into from
May 16, 2023
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
54eaf06
wip
jtschuster Apr 14, 2023
153f52a
wip
jtschuster Apr 17, 2023
39869a7
wip
jtschuster Apr 18, 2023
a5132ad
Wip
jtschuster Apr 19, 2023
b5b3004
wip
jtschuster Apr 19, 2023
b7a677c
wip
jtschuster Apr 20, 2023
8b03401
delete unused code
jtschuster Apr 20, 2023
d5b188c
More cleaup and renaming
jtschuster Apr 20, 2023
b0f0bd1
Merge branch 'main' of https://github.com/dotnet/runtime into interfa…
jtschuster Apr 20, 2023
93a9033
Add ComInterfaceContext, create diagnostics in Record constructor
jtschuster Apr 28, 2023
b3ad04c
wip
jtschuster May 1, 2023
d039410
Generate shadowing definitions and implementations
jtschuster May 4, 2023
3915490
rename
jtschuster May 4, 2023
3eba497
Don't generate Vtable methods for inherited methods
jtschuster May 4, 2023
04b8309
Stub out inherited methods on InterfaceImplementation
jtschuster May 5, 2023
5b2337a
Merge branch 'main' of https://github.com/dotnet/runtime into interfa…
jtschuster May 5, 2023
6d78a2d
Don't emit compiler generated files
jtschuster May 5, 2023
2308998
Fix test and add additional doc comments
jtschuster May 8, 2023
f6ac52b
Merge branch 'main' of https://github.com/dotnet/runtime into interfa…
jtschuster May 9, 2023
8883b28
Format and comment update
jtschuster May 9, 2023
130faae
Use the right diagnostic property
jtschuster May 9, 2023
033d817
Remove extra usings
jtschuster May 9, 2023
ae2fe39
Remove commented code, update doc comment
jtschuster May 10, 2023
299b3f3
Make methodInfo creation follow the same pattern as InterfaceInfo
jtschuster May 10, 2023
1730faa
Make methodInfo creation follow the same pattern as InterfaceInfo
jtschuster May 10, 2023
d928a89
Merge branch 'interfaceInheritanceFollowUp' of https://github.com/jts…
jtschuster May 10, 2023
f18c21c
Remove Diagnostic from ComMethodInfo
jtschuster May 10, 2023
38e6267
Create flat list of methods, group with interfaceContext so we don't
jtschuster May 12, 2023
7c1d275
Clean up, rename variables, and add comments
jtschuster May 15, 2023
9293619
Merge branch 'main' of https://github.com/dotnet/runtime into interfa…
jtschuster May 15, 2023
d78aeaf
PR Feedback
jtschuster May 15, 2023
5659559
Forgot to add new file
jtschuster May 15, 2023
2d201d1
Update src/libraries/System.Runtime.InteropServices/gen/Microsoft.Int…
jtschuster May 15, 2023
68ea987
Report diagnostic when unable to analyze code
jtschuster May 15, 2023
ec978c6
Inline local variables in HashCode
jtschuster May 15, 2023
01fa078
Return IUnknown methods in VTable for empty interface
jtschuster May 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

namespace Microsoft.Interop
{
/// <summary>
/// Provides the info necessary for copying an attribute from user code to generated code.
/// </summary>
internal sealed record AttributeInfo(ManagedTypeInfo Type, SequenceEqualImmutableArray<string> Arguments)
{
internal static AttributeInfo From(AttributeData attribute)
{
var type = ManagedTypeInfo.CreateTypeInfoForTypeSymbol(attribute.AttributeClass);
var args = attribute.ConstructorArguments.Select(ca => ca.ToCSharpString());
return new(type, args.ToSequenceEqualImmutableArray());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;

namespace Microsoft.Interop
{
public sealed partial class ComInterfaceGenerator
{
/// <summary>
/// Represents an interface and all of the methods that need to be generated for it (methods declared on the interface and methods inherited from base interfaces).
/// </summary>
private sealed record ComInterfaceAndMethodsContext(ComInterfaceContext Interface, SequenceEqualImmutableArray<ComMethodContext> Methods, SequenceEqualImmutableArray<ComMethodContext> ShadowingMethods)
{
/// <summary>
/// COM methods that are declared on the attributed interface declaration.
/// </summary>
public IEnumerable<ComMethodContext> DeclaredMethods => Methods.Where((m => m.DeclaringInterface == Interface));

/// <summary>
/// COM methods that are declared on an interface the interface inherits from.
/// </summary>
public IEnumerable<ComMethodContext> InheritedMethods => Methods.Where(m => m.DeclaringInterface != Interface);

public static IEnumerable<ComInterfaceAndMethodsContext> CalculateAllMethods(ValueEqualityImmutableDictionary<ComInterfaceContext, SequenceEqualImmutableArray<ComMethodInfo>> ifaceToDeclaredMethodsMap, StubEnvironment environment, CancellationToken ct)
{
Dictionary<ComInterfaceContext, (ImmutableArray<ComMethodContext> Methods, ImmutableArray<ComMethodContext> ShadowingMethods)> allMethodsCache = new();

foreach (var kvp in ifaceToDeclaredMethodsMap)
{
AddMethods(kvp.Key, kvp.Value);
}

return allMethodsCache.Select(kvp => new ComInterfaceAndMethodsContext(kvp.Key, kvp.Value.Methods.ToSequenceEqual(), kvp.Value.ShadowingMethods.ToSequenceEqualImmutableArray()));

(ImmutableArray<ComMethodContext> Methods, ImmutableArray<ComMethodContext> ShadowingMethods) AddMethods(ComInterfaceContext iface, IEnumerable<ComMethodInfo> declaredMethods)
{
if (allMethodsCache.TryGetValue(iface, out var cachedValue))
{
return cachedValue;
}

int startingIndex = 3;
List<ComMethodContext> methods = new();
// If we have a base interface, we should add the inherited methods to our list in vtable order
if (iface.Base is not null)
{
var baseComIface = iface.Base;
ImmutableArray<ComMethodContext> baseMethods;
if (!allMethodsCache.TryGetValue(baseComIface, out var pair))
{
baseMethods = AddMethods(baseComIface, ifaceToDeclaredMethodsMap[baseComIface]).Methods;
}
else
{
baseMethods = pair.Methods;
}
methods.AddRange(baseMethods);
}
var shadowingMethods = methods.Select(method =>
{
var info = method.MethodInfo;
var ctx = CalculateStubInformation(info.Syntax, info.Symbol, startingIndex, environment, iface.Info.Type, ct);
return new ComMethodContext(iface, info, startingIndex++, ctx);
}).ToImmutableArray();
// Then we append the declared methods in vtable order
foreach (var method in declaredMethods)
{
var ctx = CalculateStubInformation(method.Syntax, method.Symbol, startingIndex, environment, iface.Info.Type, ct);
jtschuster marked this conversation as resolved.
Show resolved Hide resolved
methods.Add(new ComMethodContext(iface, method, startingIndex++, ctx));
}
// Cache so we don't recalculate if many interfaces inherit from the same one
var finalPair = (methods.ToImmutableArray(), shadowingMethods);
allMethodsCache[iface] = finalPair;
return finalPair;
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;

namespace Microsoft.Interop
{
public sealed partial class ComInterfaceGenerator
{
private sealed record ComInterfaceContext(ComInterfaceInfo Info, ComInterfaceContext? Base)
{
/// <summary>
/// Takes a list of ComInterfaceInfo, and creates a list of ComInterfaceContext.
/// </summary>
public static IEnumerable<ComInterfaceContext> GetContexts(ImmutableArray<ComInterfaceInfo> data, CancellationToken _)
{
Dictionary<string, ComInterfaceInfo> symbolToInterfaceInfoMap = new();
foreach (var iface in data)
{
symbolToInterfaceInfoMap.Add(iface.ThisInterfaceKey, iface);
}
Dictionary<string, ComInterfaceContext> symbolToContextMap = new();

foreach (var iface in data)
{
yield return AddContext(iface);
}

ComInterfaceContext AddContext(ComInterfaceInfo iface)
{
if (symbolToContextMap.TryGetValue(iface.ThisInterfaceKey, out var cachedValue))
{
return cachedValue;
}

if (iface.BaseInterfaceKey is null)
{
var baselessCtx = new ComInterfaceContext(iface, null);
symbolToContextMap[iface.ThisInterfaceKey] = baselessCtx;
return baselessCtx;
}

if (!symbolToContextMap.TryGetValue(iface.BaseInterfaceKey, out var baseContext))
{
baseContext = AddContext(symbolToInterfaceInfoMap[iface.BaseInterfaceKey]);
}
var ctx = new ComInterfaceContext(iface, baseContext);
symbolToContextMap[iface.ThisInterfaceKey] = ctx;
return ctx;
}
}
}
}
}
Loading