From b45021633aa10cb905dad0042b668543c34b6d8f Mon Sep 17 00:00:00 2001 From: Sophia Chen Date: Thu, 13 Feb 2025 13:47:30 -0800 Subject: [PATCH 1/7] init commit --- src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs | 8 ++++++++ src/cswinrt/code_writers.h | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs b/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs index 7a4a0b4bd..0e00e2906 100644 --- a/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs +++ b/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs @@ -240,6 +240,14 @@ private static (VtableAttribute, EquatableArray) GetVtableAttri { var isManagedOnlyType = GeneratorHelper.IsManagedOnlyType(compilation); var isWinRTTypeFunc = GeneratorHelper.IsWinRTType(compilation, checkForComponentTypes); + var isAbstractType = GeneratorHelper.IsAbstractType(compilation); + + //This conditional will need to go somewhere else, but it is here for now to show the logic + if (isAbstractType(symbol) && 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/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index 9a87ec272..eba253aac 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 % : % { )", +"[global::WinRT.WindowsRuntimeType]", bind(type, true), "public", "abstract", From 1fb02ca0e91d5259fa932b4c4be871fcb986a839 Mon Sep 17 00:00:00 2001 From: Sophia Chen Date: Thu, 13 Feb 2025 13:49:45 -0800 Subject: [PATCH 2/7] fix abstract --- src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs b/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs index 0e00e2906..a72da1713 100644 --- a/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs +++ b/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs @@ -240,10 +240,9 @@ private static (VtableAttribute, EquatableArray) GetVtableAttri { var isManagedOnlyType = GeneratorHelper.IsManagedOnlyType(compilation); var isWinRTTypeFunc = GeneratorHelper.IsWinRTType(compilation, checkForComponentTypes); - var isAbstractType = GeneratorHelper.IsAbstractType(compilation); //This conditional will need to go somewhere else, but it is here for now to show the logic - if (isAbstractType(symbol) && isWinRTTypeFunc(symbol, typeMapper)) + if (symbol.IsAbstract && isWinRTTypeFunc(symbol, typeMapper)) { Console.WriteLine($"HelloWorld: Abstract type {symbol} is correctly labeled as detected as abstract"); } From c866a6979caa5614e2ed3e495dd76ffeec7da742 Mon Sep 17 00:00:00 2001 From: Sophia Chen Date: Tue, 25 Feb 2025 17:21:11 -0800 Subject: [PATCH 3/7] changes for the guid stuff --- .../WinRT.SourceGenerator/WinRTTypeWriter.cs | 81 ++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs b/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs index 56066b306..2bc36069a 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs +++ b/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs @@ -1612,7 +1612,7 @@ private void AddGuidAttribute(EntityHandle parentHandle, Guid guid) byteArray[12], byteArray[13], byteArray[14], - byteArray[15] + byteArray[15] }; AddCustomAttributes("Windows.Foundation.Metadata.GuidAttribute", types, arguments, parentHandle); @@ -2454,7 +2454,15 @@ classMember.Key is IMethodSymbol constructorMethod && } AddDefaultVersionAttribute(typeDefinitionHandle, GetVersion(classSymbol, true)); - AddGuidAttribute(typeDefinitionHandle, interfaceName); + // bookmarking + Logger.Log("HelloWorld: the interfaceName is " + interfaceName); + Logger.Log("HelloWorld: Class Symbol is " + classSymbol.ToString()); + if (!GetProjectionsDefaultInterfaceGuid(classSymbol, typeDefinitionHandle, classDeclaration)) + { + Logger.Log("adding a new guid attribute"); + AddGuidAttribute(typeDefinitionHandle, interfaceName); + } + AddExclusiveToAttribute(typeDefinitionHandle, classSymbol.ToString()); AddOverloadAttributeForInterfaceMethods(typeDeclaration); @@ -2716,6 +2724,75 @@ public void FinalizeGeneration() } } + public bool GetProjectionsDefaultInterfaceGuid(INamedTypeSymbol symbol, TypeDefinitionHandle handle, TypeDeclaration classDeclaration) + { + bool IsWinRTType(ISymbol symbol, TypeMapper mapper) + { + if (symbol is INamedTypeSymbol namedType) + { + if (namedType.TypeKind == TypeKind.Interface) + { + // Interfaces which are allowed to be implemented on authored types but + // aren't WinRT interfaces. + return !ImplementedInterfacesWithoutMapping.Contains(QualifiedName(namedType)); + } + + return namedType.SpecialType != SpecialType.System_Object && + namedType.SpecialType != SpecialType.System_Enum && + namedType.SpecialType != SpecialType.System_ValueType && + namedType.SpecialType != SpecialType.System_Delegate && + namedType.SpecialType != SpecialType.System_MulticastDelegate; + } + + // In an authoring component, diagnostics prevents you from using non-WinRT types + // by the time we get to here. + return true; + } + + + Logger.Log("HelloWorld: Start of our logic"); + Logger.Log("handle is " + handle.ToString()); + Guid guid = new Guid(); + + var baseAbstractClass = symbol.BaseType; + if (baseAbstractClass != null && baseAbstractClass.IsAbstract && IsWinRTType(baseAbstractClass, mapper)) + { + Logger.Log("HelloWorld: Inside the flag condition"); + Logger.Log("The abstract base class is " + baseAbstractClass); + + if (classDeclaration.DefaultInterface != null) + { + Logger.Log("HelloWorld: There is a default class class " + classDeclaration.DefaultInterface); + + // 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) + { + Logger.Log("HelloWorld: There is an attribute named ProjectRuntimeClass"); + projectedType.TryGetAttributeWithType(Model.Compilation.GetTypeByMetadataName("System.Runtime.InteropServices.GuidAttribute"), out AttributeData guidAttr); + if (guidAttr != null && guidAttr.ConstructorArguments.Length == 1) + { + Logger.Log("HelloWorld: There is an attribute named GUID. Just added the GUID."); + string guidString = guidAttr.ConstructorArguments[0].Value as string; + Logger.Log("The guid is " + guidString); + if (!string.IsNullOrEmpty(guidString) && Guid.TryParse(guidString, out Guid parsedGuid)) + { + Logger.Log("The guid is parsed"); + guid = parsedGuid; + + AddGuidAttribute(handle, guid); + Logger.Log("The guid is added"); + + return true; + } + } + } + } + } + + return false; + } public void GenerateWinRTExposedClassAttributes(GeneratorExecutionContext context) { bool IsWinRTType(ISymbol symbol, TypeMapper mapper) From 20310a2c7423845073b3e730e4dfcc44193ac024 Mon Sep 17 00:00:00 2001 From: Sophia Chen Date: Tue, 4 Mar 2025 14:02:31 -0800 Subject: [PATCH 4/7] implementing the activation directly --- .../WinRT.SourceGenerator/WinRTTypeWriter.cs | 26 +------------------ src/cswinrt/code_writers.h | 11 ++++++-- 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs b/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs index 2bc36069a..b852d6ed2 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs +++ b/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs @@ -2726,36 +2726,12 @@ public void FinalizeGeneration() public bool GetProjectionsDefaultInterfaceGuid(INamedTypeSymbol symbol, TypeDefinitionHandle handle, TypeDeclaration classDeclaration) { - bool IsWinRTType(ISymbol symbol, TypeMapper mapper) - { - if (symbol is INamedTypeSymbol namedType) - { - if (namedType.TypeKind == TypeKind.Interface) - { - // Interfaces which are allowed to be implemented on authored types but - // aren't WinRT interfaces. - return !ImplementedInterfacesWithoutMapping.Contains(QualifiedName(namedType)); - } - - return namedType.SpecialType != SpecialType.System_Object && - namedType.SpecialType != SpecialType.System_Enum && - namedType.SpecialType != SpecialType.System_ValueType && - namedType.SpecialType != SpecialType.System_Delegate && - namedType.SpecialType != SpecialType.System_MulticastDelegate; - } - - // In an authoring component, diagnostics prevents you from using non-WinRT types - // by the time we get to here. - return true; - } - - Logger.Log("HelloWorld: Start of our logic"); Logger.Log("handle is " + handle.ToString()); Guid guid = new Guid(); var baseAbstractClass = symbol.BaseType; - if (baseAbstractClass != null && baseAbstractClass.IsAbstract && IsWinRTType(baseAbstractClass, mapper)) + if (baseAbstractClass != null && baseAbstractClass.IsAbstract && GeneratorHelper.IsWinRTType(baseAbstractClass, mapper)) { Logger.Log("HelloWorld: Inside the flag condition"); Logger.Log("The abstract base class is " + baseAbstractClass); diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index eba253aac..47cfdd4ad 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -8732,7 +8732,7 @@ bind_list(", ", signature.params())); auto abstract_type_name = "Abstract" + type_name; w.write(R"( %% -% % class % : % { +% % class % : %, ICustomQueryInterface { )", "[global::WinRT.WindowsRuntimeType]", bind(type, true), @@ -8767,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"); From 20851fd02cb6db2846a86f31ab3b0e70f70a3257 Mon Sep 17 00:00:00 2001 From: Sophia Chen Date: Tue, 4 Mar 2025 14:13:35 -0800 Subject: [PATCH 5/7] get rid of comments --- .../WinRT.SourceGenerator/WinRTTypeWriter.cs | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs b/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs index b852d6ed2..622fe4bbb 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs +++ b/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs @@ -2454,12 +2454,9 @@ classMember.Key is IMethodSymbol constructorMethod && } AddDefaultVersionAttribute(typeDefinitionHandle, GetVersion(classSymbol, true)); - // bookmarking - Logger.Log("HelloWorld: the interfaceName is " + interfaceName); - Logger.Log("HelloWorld: Class Symbol is " + classSymbol.ToString()); + if (!GetProjectionsDefaultInterfaceGuid(classSymbol, typeDefinitionHandle, classDeclaration)) { - Logger.Log("adding a new guid attribute"); AddGuidAttribute(typeDefinitionHandle, interfaceName); } @@ -2726,40 +2723,26 @@ public void FinalizeGeneration() public bool GetProjectionsDefaultInterfaceGuid(INamedTypeSymbol symbol, TypeDefinitionHandle handle, TypeDeclaration classDeclaration) { - Logger.Log("HelloWorld: Start of our logic"); - Logger.Log("handle is " + handle.ToString()); Guid guid = new Guid(); var baseAbstractClass = symbol.BaseType; if (baseAbstractClass != null && baseAbstractClass.IsAbstract && GeneratorHelper.IsWinRTType(baseAbstractClass, mapper)) { - Logger.Log("HelloWorld: Inside the flag condition"); - Logger.Log("The abstract base class is " + baseAbstractClass); - if (classDeclaration.DefaultInterface != null) { - Logger.Log("HelloWorld: There is a default class class " + classDeclaration.DefaultInterface); - // 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) { - Logger.Log("HelloWorld: There is an attribute named ProjectRuntimeClass"); projectedType.TryGetAttributeWithType(Model.Compilation.GetTypeByMetadataName("System.Runtime.InteropServices.GuidAttribute"), out AttributeData guidAttr); if (guidAttr != null && guidAttr.ConstructorArguments.Length == 1) { - Logger.Log("HelloWorld: There is an attribute named GUID. Just added the GUID."); string guidString = guidAttr.ConstructorArguments[0].Value as string; - Logger.Log("The guid is " + guidString); if (!string.IsNullOrEmpty(guidString) && Guid.TryParse(guidString, out Guid parsedGuid)) { - Logger.Log("The guid is parsed"); guid = parsedGuid; - AddGuidAttribute(handle, guid); - Logger.Log("The guid is added"); - return true; } } From 61198dad4ef5d2f2bf77abd048b934c587ecba83 Mon Sep 17 00:00:00 2001 From: Sophia Chen Date: Fri, 7 Mar 2025 15:48:50 -0800 Subject: [PATCH 6/7] re order the methods --- .../WinRT.SourceGenerator/WinRTTypeWriter.cs | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs b/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs index 622fe4bbb..bf2903b45 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs +++ b/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs @@ -1612,7 +1612,7 @@ private void AddGuidAttribute(EntityHandle parentHandle, Guid guid) byteArray[12], byteArray[13], byteArray[14], - byteArray[15] + byteArray[15] }; AddCustomAttributes("Windows.Foundation.Metadata.GuidAttribute", types, arguments, parentHandle); @@ -2369,6 +2369,11 @@ void CheckAndMarkSymbolForAttributes(ISymbol symbol) currentTypeDeclaration.SymbolsWithAttributes.Add(symbol); } } + bool IsMatchingMember(ISymbol symbol, ISymbol memberNode) + { + return symbol.Name == memberNode.Name && + symbol.Kind == memberNode.Kind; + } void AddSynthesizedInterface( TypeDeclaration classDeclaration, @@ -2381,9 +2386,36 @@ 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 = 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); + } + } + // 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 && @@ -2735,6 +2767,7 @@ public bool GetProjectionsDefaultInterfaceGuid(INamedTypeSymbol symbol, TypeDefi 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) { From dfca60d1846d941d0b42596d930a95b979b116ab Mon Sep 17 00:00:00 2001 From: Sophia Chen Date: Fri, 7 Mar 2025 15:55:02 -0800 Subject: [PATCH 7/7] reorder the method --- .../WinRT.SourceGenerator/WinRTTypeWriter.cs | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs b/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs index bf2903b45..866f3c52b 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs +++ b/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs @@ -2375,20 +2375,9 @@ bool IsMatchingMember(ISymbol symbol, ISymbol memberNode) symbol.Kind == memberNode.Kind; } - void AddSynthesizedInterface( - TypeDeclaration classDeclaration, - SynthesizedInterfaceType interfaceType, - HashSet classMembersFromInterfaces) + Dictionary> GetOrderedMethods(INamedTypeSymbol classSymbol, TypeDeclaration classDeclaration) { - var typeDeclaration = new TypeDeclaration(); - currentTypeDeclaration = typeDeclaration; - - 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 = classDeclaration.MethodDefinitions; - var baseAbstractClass = classSymbol.BaseType; if (baseAbstractClass != null && baseAbstractClass.IsAbstract && GeneratorHelper.IsWinRTType(baseAbstractClass, mapper)) { @@ -2398,7 +2387,7 @@ void AddSynthesizedInterface( { var orderedMembers = projectedType.GetMembers().ToList(); var orderedMethodDefinitions = classDeclaration.MethodDefinitions - .Where(def => orderedMembers.Any(member => IsMatchingMember(def.Key, member))) + .Where(def => orderedMembers.Any(member => IsMatchingMember(def.Key, member))) .OrderBy(def => orderedMembers.FindIndex(member => IsMatchingMember(def.Key, member))) .ToList(); @@ -2411,6 +2400,22 @@ void AddSynthesizedInterface( methodDefs = orderedMethodDefinitions.ToDictionary(kvp => kvp.Key, kvp => kvp.Value, SymbolEqualityComparer.Default); } } + return methodDefs; + } + + void AddSynthesizedInterface( + TypeDeclaration classDeclaration, + SynthesizedInterfaceType interfaceType, + HashSet classMembersFromInterfaces) + { + var typeDeclaration = new TypeDeclaration(); + currentTypeDeclaration = typeDeclaration; + + 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.