diff --git a/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs b/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs index 7a4a0b4bd..a72da1713 100644 --- a/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs +++ b/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs @@ -240,6 +240,13 @@ private static (VtableAttribute, EquatableArray) GetVtableAttri { var isManagedOnlyType = GeneratorHelper.IsManagedOnlyType(compilation); var isWinRTTypeFunc = GeneratorHelper.IsWinRTType(compilation, checkForComponentTypes); + + //This conditional will need to go somewhere else, but it is here for now to show the logic + if (symbol.IsAbstract && isWinRTTypeFunc(symbol, typeMapper)) + { + Console.WriteLine($"HelloWorld: Abstract type {symbol} is correctly labeled as detected as abstract"); + } + var vtableAttribute = GetVtableAttributeToAdd(symbol, isManagedOnlyType, isWinRTTypeFunc, typeMapper, compilation, false); if (vtableAttribute != default) { diff --git a/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs b/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs index 56066b306..866f3c52b 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs +++ b/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs @@ -2369,6 +2369,39 @@ void CheckAndMarkSymbolForAttributes(ISymbol symbol) currentTypeDeclaration.SymbolsWithAttributes.Add(symbol); } } + bool IsMatchingMember(ISymbol symbol, ISymbol memberNode) + { + return symbol.Name == memberNode.Name && + symbol.Kind == memberNode.Kind; + } + + Dictionary> GetOrderedMethods(INamedTypeSymbol classSymbol, TypeDeclaration classDeclaration) + { + var methodDefs = classDeclaration.MethodDefinitions; + var baseAbstractClass = classSymbol.BaseType; + if (baseAbstractClass != null && baseAbstractClass.IsAbstract && GeneratorHelper.IsWinRTType(baseAbstractClass, mapper)) + { + var projectedAttr = baseAbstractClass.BaseType.GetAttributes().FirstOrDefault(attr => attr.AttributeClass?.Name == "ProjectedRuntimeClassAttribute"); + + if (projectedAttr != null && projectedAttr.ConstructorArguments.Length == 1 && projectedAttr.ConstructorArguments[0].Value is INamedTypeSymbol projectedType) + { + var orderedMembers = projectedType.GetMembers().ToList(); + var orderedMethodDefinitions = classDeclaration.MethodDefinitions + .Where(def => orderedMembers.Any(member => IsMatchingMember(def.Key, member))) + .OrderBy(def => orderedMembers.FindIndex(member => IsMatchingMember(def.Key, member))) + .ToList(); + + var extraMethodDefinitions = classDeclaration.MethodDefinitions + .Where(def => !orderedMembers.Any(member => IsMatchingMember(def.Key, member))) + .ToList(); + + orderedMethodDefinitions.AddRange(extraMethodDefinitions); + + methodDefs = orderedMethodDefinitions.ToDictionary(kvp => kvp.Key, kvp => kvp.Value, SymbolEqualityComparer.Default); + } + } + return methodDefs; + } void AddSynthesizedInterface( TypeDeclaration classDeclaration, @@ -2381,9 +2414,13 @@ void AddSynthesizedInterface( bool hasTypes = false; INamedTypeSymbol classSymbol = classDeclaration.Node as INamedTypeSymbol; + // If it is the case of our special abstract class, we will order the methods per the order in the projections. + var methodDefs = GetOrderedMethods(classSymbol, classDeclaration); + // Each class member results in some form of method definition, // so using that to our advantage to get public members. - foreach (var classMember in classDeclaration.MethodDefinitions) + + foreach (var classMember in methodDefs) { if (interfaceType == SynthesizedInterfaceType.Factory && classMember.Key is IMethodSymbol constructorMethod && @@ -2454,7 +2491,12 @@ classMember.Key is IMethodSymbol constructorMethod && } AddDefaultVersionAttribute(typeDefinitionHandle, GetVersion(classSymbol, true)); - AddGuidAttribute(typeDefinitionHandle, interfaceName); + + if (!GetProjectionsDefaultInterfaceGuid(classSymbol, typeDefinitionHandle, classDeclaration)) + { + AddGuidAttribute(typeDefinitionHandle, interfaceName); + } + AddExclusiveToAttribute(typeDefinitionHandle, classSymbol.ToString()); AddOverloadAttributeForInterfaceMethods(typeDeclaration); @@ -2716,6 +2758,38 @@ public void FinalizeGeneration() } } + public bool GetProjectionsDefaultInterfaceGuid(INamedTypeSymbol symbol, TypeDefinitionHandle handle, TypeDeclaration classDeclaration) + { + Guid guid = new Guid(); + + var baseAbstractClass = symbol.BaseType; + if (baseAbstractClass != null && baseAbstractClass.IsAbstract && GeneratorHelper.IsWinRTType(baseAbstractClass, mapper)) + { + if (classDeclaration.DefaultInterface != null) + { + // Get the guid of the projections class + var projectedAttr = baseAbstractClass.BaseType.GetAttributes().FirstOrDefault(attr => attr.AttributeClass?.Name == "ProjectedRuntimeClassAttribute"); + + if (projectedAttr != null && projectedAttr.ConstructorArguments.Length == 1 && projectedAttr.ConstructorArguments[0].Value is INamedTypeSymbol projectedType) + { + projectedType.DeclaringSyntaxReferences.FirstOrDefault(); + projectedType.TryGetAttributeWithType(Model.Compilation.GetTypeByMetadataName("System.Runtime.InteropServices.GuidAttribute"), out AttributeData guidAttr); + if (guidAttr != null && guidAttr.ConstructorArguments.Length == 1) + { + string guidString = guidAttr.ConstructorArguments[0].Value as string; + if (!string.IsNullOrEmpty(guidString) && Guid.TryParse(guidString, out Guid parsedGuid)) + { + guid = parsedGuid; + AddGuidAttribute(handle, guid); + return true; + } + } + } + } + } + + return false; + } public void GenerateWinRTExposedClassAttributes(GeneratorExecutionContext context) { bool IsWinRTType(ISymbol symbol, TypeMapper mapper) diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index 9a87ec272..47cfdd4ad 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -8731,8 +8731,10 @@ bind_list(", ", signature.params())); auto type_name = write_type_name_temp(w, type); auto abstract_type_name = "Abstract" + type_name; w.write(R"( -%% % class % : % { +%% +% % class % : %, ICustomQueryInterface { )", +"[global::WinRT.WindowsRuntimeType]", bind(type, true), "public", "abstract", @@ -8765,8 +8767,15 @@ public %() : base(WinRT.DerivedComposed.Instance) abstract_type_name ); } - + w.write(R"( +global::System.Runtime.InteropServices.CustomQueryInterfaceResult global::System.Runtime.InteropServices.ICustomQueryInterface.GetInterface(ref Guid iid, out IntPtr ppv) +{ + ppv = IntPtr.Zero; + return global::System.Runtime.InteropServices.CustomQueryInterfaceResult.NotHandled; +} +)"); + for (auto&& ii : type.InterfaceImpl()) { auto is_overridable = has_attribute(ii, "Windows.Foundation.Metadata", "OverridableAttribute");