diff --git a/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs b/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs index 9703ed882..00fbf0166 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs +++ b/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs @@ -935,25 +935,35 @@ internal static (string, string, string, bool, bool) GetSystemTypeCustomMapping( private void ProcessCustomMappedInterfaces(INamedTypeSymbol classSymbol) { Logger.Log("writing custom mapped interfaces for " + QualifiedName(classSymbol)); + Dictionary isPublicImplementation = new Dictionary(); + // Mark custom mapped interface members for removal later. // Note we want to also mark members from interfaces without mappings. foreach (var implementedInterface in GetInterfaces(classSymbol, true). Where(symbol => MappedCSharpTypes.ContainsKey(QualifiedName(symbol)) || ImplementedInterfacesWithoutMapping.Contains(QualifiedName(symbol)))) { - string interfaceName = QualifiedName(implementedInterface); - Logger.Log("custom mapped interface: " + interfaceName); + bool isPubliclyImplemented = false; + Logger.Log("custom mapped interface: " + QualifiedName(implementedInterface, true)); foreach (var interfaceMember in implementedInterface.GetMembers()) { var classMember = classSymbol.FindImplementationForInterfaceMember(interfaceMember); currentTypeDeclaration.CustomMappedSymbols.Add(classMember); + + // For custom mapped interfaces, we don't have 1 to 1 mapping of members between the mapped from + // and mapped to interface and due to that we need to decide if the mapped inteface as a whole + // is public or not (explicitly implemented). Due to that, as long as one member is not + // explicitly implemented (i.e accessible via the class), we treat the entire mapped interface + // also as accessible via the class. + isPubliclyImplemented |= (classMember.DeclaredAccessibility == Accessibility.Public); } + isPublicImplementation[implementedInterface] = isPubliclyImplemented; } foreach (var implementedInterface in GetInterfaces(classSymbol) .Where(symbol => MappedCSharpTypes.ContainsKey(QualifiedName(symbol)))) { - WriteCustomMappedTypeMembers(implementedInterface, true); + WriteCustomMappedTypeMembers(implementedInterface, true, isPublicImplementation[implementedInterface]); } } @@ -975,17 +985,42 @@ INamedTypeSymbol GetTypeByMetadataName(string metadataName) return types.FirstOrDefault(); } - private void WriteCustomMappedTypeMembers(INamedTypeSymbol symbol, bool isDefinition) + // Convert the entire type name including the generic types to WinMD format. + private string GetMappedQualifiedTypeName(ITypeSymbol symbol) + { + string qualifiedName = QualifiedName(symbol); + if (MappedCSharpTypes.ContainsKey(qualifiedName)) + { + var (@namespace, mappedTypeName, _, _, _) = MappedCSharpTypes[qualifiedName].GetMapping(currentTypeDeclaration.Node); + qualifiedName = QualifiedName(@namespace, mappedTypeName); + if (symbol is INamedTypeSymbol namedType && namedType.TypeArguments.Length > 0) + { + return string.Format("{0}<{1}>", qualifiedName, string.Join(", ", namedType.TypeArguments.Select(type => GetMappedQualifiedTypeName(type)))); + } + } + else if((symbol.ContainingNamespace.ToString() == "System" && symbol.IsValueType) || qualifiedName == "System.String") + { + // WinRT fundamental types + return symbol.Name; + } + + return qualifiedName; + } + + private void WriteCustomMappedTypeMembers(INamedTypeSymbol symbol, bool isDefinition, bool isPublic = true) { var (_, mappedTypeName, _, _, _) = MappedCSharpTypes[QualifiedName(symbol)].GetMapping(currentTypeDeclaration.Node); - Logger.Log("writing custom mapped type members for " + mappedTypeName); + string qualifiedName = GetMappedQualifiedTypeName(symbol); + + Logger.Log("writing custom mapped type members for " + mappedTypeName + " public: " + isPublic + " qualified name: " + qualifiedName); void AddMethod(string name, Parameter[] parameters, Symbol returnType) { parameters ??= new Parameter[0]; if (isDefinition) { - var methodDefinitionHandle = AddMethodDefinition(name, parameters, returnType, false, false); - currentTypeDeclaration.AddMethod(symbol, name, methodDefinitionHandle); + var methodName = isPublic ? name : QualifiedName(qualifiedName, name); + var methodDefinitionHandle = AddMethodDefinition(methodName, parameters, returnType, false, false, false, isPublic); + currentTypeDeclaration.AddMethod(symbol, methodName, methodDefinitionHandle); } else { @@ -998,7 +1033,8 @@ void AddProperty(string name, Symbol type, bool setProperty) { if (isDefinition) { - AddPropertyDefinition(name, type, symbol, setProperty, false); + var propertyName = isPublic ? name : QualifiedName(qualifiedName, name); + AddPropertyDefinition(propertyName, type, symbol, setProperty, false, isPublic); } else { @@ -1010,7 +1046,8 @@ void AddEvent(string name, Symbol eventType) { if (isDefinition) { - AddEventDeclaration(name, eventType.Type, symbol, false); + var eventName = isPublic ? name : QualifiedName(qualifiedName, name); + AddEventDeclaration(eventName, eventType.Type, symbol, false, isPublic); } else { @@ -2419,14 +2456,14 @@ void AddProjectedType(INamedTypeSymbol type, string projectedTypeOverride = null } } - typeDefinitionMapping[projectedTypeOverride ?? QualifiedName(type)] = currentTypeDeclaration; + typeDefinitionMapping[projectedTypeOverride ?? QualifiedName(type, true)] = currentTypeDeclaration; } void AddMappedType(INamedTypeSymbol type) { currentTypeDeclaration = new TypeDeclaration(type); WriteCustomMappedTypeMembers(type, false); - typeDefinitionMapping[QualifiedName(type)] = currentTypeDeclaration; + typeDefinitionMapping[QualifiedName(type, true)] = currentTypeDeclaration; } enum SynthesizedInterfaceType @@ -2709,15 +2746,15 @@ public void FinalizeGeneration() Logger.Log("finalizing class " + QualifiedName(classSymbol)); foreach (var implementedInterface in GetInterfaces(classSymbol)) { - var implementedInterfaceQualifiedName = QualifiedName(implementedInterface); - if (!typeDefinitionMapping.ContainsKey(implementedInterfaceQualifiedName)) + var implementedInterfaceQualifiedNameWithGenerics = QualifiedName(implementedInterface, true); + if (!typeDefinitionMapping.ContainsKey(implementedInterfaceQualifiedNameWithGenerics)) { AddType(implementedInterface); } - Logger.Log("finalizing interface " + implementedInterfaceQualifiedName); - var interfaceTypeDeclaration = typeDefinitionMapping[implementedInterfaceQualifiedName]; - if (MappedCSharpTypes.ContainsKey(implementedInterfaceQualifiedName)) + Logger.Log("finalizing interface " + implementedInterfaceQualifiedNameWithGenerics); + var interfaceTypeDeclaration = typeDefinitionMapping[implementedInterfaceQualifiedNameWithGenerics]; + if (MappedCSharpTypes.ContainsKey(QualifiedName(implementedInterface))) { Logger.Log("adding MethodImpls for custom mapped interface"); foreach (var interfaceMember in interfaceTypeDeclaration.MethodReferences) @@ -2814,9 +2851,10 @@ public void FinalizeGeneration() foreach (var interfaceDeclaration in interfaceDeclarations) { INamedTypeSymbol interfaceSymbol = interfaceDeclaration.Node as INamedTypeSymbol; - if (typeDefinitionMapping[QualifiedName(interfaceSymbol)].Handle != default && GetVersion(interfaceSymbol) == -1) + string qualifiedNameWithGenerics = QualifiedName(interfaceSymbol, true); + if (typeDefinitionMapping[qualifiedNameWithGenerics].Handle != default && GetVersion(interfaceSymbol) == -1) { - AddDefaultVersionAttribute(typeDefinitionMapping[QualifiedName(interfaceSymbol)].Handle); + AddDefaultVersionAttribute(typeDefinitionMapping[qualifiedNameWithGenerics].Handle); } } @@ -2900,19 +2938,23 @@ public string QualifiedName(string @namespace, string identifier) return string.Join(".", @namespace, identifier); } - public static string GetGenericName(ISymbol symbol) + public static string GetGenericName(ISymbol symbol, bool includeGenerics = false) { string name = symbol.Name; if (symbol is INamedTypeSymbol namedType && namedType.TypeArguments.Length != 0) { name += "`" + namedType.TypeArguments.Length; + if(includeGenerics) + { + name += string.Format("<{0}>", string.Join(", ", namedType.TypeArguments)); + } } return name; } - public string QualifiedName(ISymbol symbol) + public string QualifiedName(ISymbol symbol, bool includeGenerics = false) { - return QualifiedName(symbol.ContainingNamespace.ToString(), GetGenericName(symbol)); + return QualifiedName(symbol.ContainingNamespace.ToString(), GetGenericName(symbol, includeGenerics)); } public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) diff --git a/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.exe.manifest b/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.exe.manifest index 4611a9a64..1ae950c06 100644 --- a/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.exe.manifest +++ b/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.exe.manifest @@ -14,6 +14,10 @@ name="AuthoringTest.CustomDictionary" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" /> + + + vector = multipleInterfaces; + Microsoft::UI::Xaml::Interop::IBindableVector bindableVector = multipleInterfaces; + EXPECT_EQ(vector.Size(), 0); + EXPECT_EQ(bindableVector.Size(), 0); + vector.Append(DisposableClass()); + vector.Append(DisposableClass()); + vector.Append(disposed); + bindableVector.Append(DisposableClass()); + EXPECT_EQ(vector.Size(), 4); + EXPECT_EQ(bindableVector.Size(), 4); + + auto first = vector.First(); + EXPECT_TRUE(first.HasCurrent()); + EXPECT_FALSE(first.Current().IsDisposed()); + auto bindableFirst = bindable.First(); + EXPECT_TRUE(bindableFirst.HasCurrent()); + EXPECT_FALSE(bindableFirst.Current().as().IsDisposed()); + bindableFirst.Current().as().Close(); + EXPECT_TRUE(first.Current().IsDisposed()); + EXPECT_FALSE(vector.GetAt(1).IsDisposed()); + EXPECT_TRUE(vector.GetAt(2).IsDisposed()); + EXPECT_TRUE(bindableVector.First().Current().as().IsDisposed()); + EXPECT_FALSE(bindableVector.GetAt(3).as().IsDisposed()); + EXPECT_TRUE(bindableVector.GetAt(2).as().IsDisposed()); + for (auto obj : vector.GetView()) + { + obj.Close(); + } + + std::array view{}; + EXPECT_EQ(vector.GetMany(1, view), 2); + EXPECT_EQ(view.size(), 2); + for (auto& obj : view) + { + EXPECT_TRUE(obj.IsDisposed()); + } + + CustomDictionary2 dictionary; + + EXPECT_FALSE(dictionary.Insert(L"first", 1)); + EXPECT_FALSE(dictionary.Insert(L"second", 2)); + EXPECT_TRUE(dictionary.Insert(L"second", 4)); + EXPECT_FALSE(dictionary.Insert(L"third", 4)); + EXPECT_EQ(dictionary.Size(), 3); + + EXPECT_TRUE(dictionary.HasKey(L"first")); + EXPECT_FALSE(dictionary.HasKey(L"fourth")); + EXPECT_TRUE(dictionary.HasKey(L"third")); + + dictionary.Clear(); + EXPECT_FALSE(dictionary.HasKey(L"first")); + EXPECT_FALSE(dictionary.HasKey(L"fourth")); + EXPECT_FALSE(dictionary.HasKey(L"third")); } \ No newline at end of file diff --git a/src/Tests/AuthoringTest/Program.cs b/src/Tests/AuthoringTest/Program.cs index 7b0bda984..b6d3a2b2b 100644 --- a/src/Tests/AuthoringTest/Program.cs +++ b/src/Tests/AuthoringTest/Program.cs @@ -270,6 +270,17 @@ public static int GetDefaultNumber() return 2; } + public static int DefaultNumber { get; set; } + + internal static int DefaultNumber2 { get; set; } + + public static event BasicDelegate StaticDelegateEvent; + + public static void FireStaticDelegate(uint value) + { + StaticDelegateEvent?.Invoke(value); + } + // Default interface public void FireBasicDelegate(uint value) @@ -795,6 +806,17 @@ public static int GetNumber(int number) { return number; } + + public static int Number { get; set; } + + internal static int Number2 { get; set; } + + public static event DoubleDelegate DelegateEvent; + + public static void FireDelegate(double value) + { + DelegateEvent?.Invoke(value); + } } public static class ButtonUtils @@ -953,6 +975,29 @@ public IEnumerable GetErrors(string propertyName) } } + public sealed class CustomNotifyDataErrorInfo2 : INotifyDataErrorInfo + { + bool INotifyDataErrorInfo.HasErrors => throw new NotImplementedException(); + + event EventHandler INotifyDataErrorInfo.ErrorsChanged + { + add + { + throw new NotImplementedException(); + } + + remove + { + throw new NotImplementedException(); + } + } + + IEnumerable INotifyDataErrorInfo.GetErrors(string propertyName) + { + throw new NotImplementedException(); + } + } + public sealed class CustomEnumerable : IEnumerable { private IEnumerable _enumerable; @@ -973,17 +1018,17 @@ public sealed class CustomXamlMetadataProvider : IXamlMetadataProvider // Tests DefaultOverload attribute specified in projected interface. public IXamlType GetXamlType(Type type) { - throw new NotImplementedException(); + return null; } public IXamlType GetXamlType(string fullName) { - throw new NotImplementedException(); + return null; } public XmlnsDefinition[] GetXmlnsDefinitions() { - throw new NotImplementedException(); + return null; } } @@ -1168,4 +1213,228 @@ IEnumerator IEnumerable.GetEnumerator() throw new NotImplementedException(); } } + + public interface IInterfaceInheritance : IDouble, IWwwFormUrlDecoderEntry + { + void SetNumber(double number); + } + + public sealed class InterfaceInheritance : IInterfaceInheritance + { + private double _number; + public double Number { get => _number; set => _number = value; } + + public string Name => "IInterfaceInheritance"; + + public string Value => "InterfaceInheritance"; + + public event DoubleDelegate DoubleDelegateEvent; + + public double GetDouble() + { + return 2; + } + + public double GetDouble(bool ignoreFactor) + { + return 2.5; + } + + public string GetNumStr(int num) + { + return num.ToString(); + } + + public string GetNumStr(double num) + { + return num.ToString(); + } + + public void SetNumber(double number) + { + Number = number; + } + } + + public sealed class MultipleInterfaceMappingClass : IList, IList + { + private List _list = new List(); + + DisposableClass IList.this[int index] { get => _list[index]; set => _list[index] = value; } + object IList.this[int index] { get => _list[index]; set => ((IList)_list) [index] = value; } + + int ICollection.Count => _list.Count; + + int ICollection.Count => _list.Count; + + bool ICollection.IsReadOnly => true; + + bool IList.IsReadOnly => true; + + bool IList.IsFixedSize => false; + + bool ICollection.IsSynchronized => true; + + object ICollection.SyncRoot => ((ICollection) _list).SyncRoot; + + void ICollection.Add(DisposableClass item) + { + _list.Add(item); + } + + int IList.Add(object value) + { + return ((IList) _list).Add(value); + } + + void ICollection.Clear() + { + _list.Clear(); + } + + void IList.Clear() + { + _list.Clear(); + } + + bool ICollection.Contains(DisposableClass item) + { + return _list.Contains(item); + } + + bool IList.Contains(object value) + { + return ((IList) _list).Contains(value); + } + + void ICollection.CopyTo(DisposableClass[] array, int arrayIndex) + { + _list.CopyTo(array, arrayIndex); + } + + void ICollection.CopyTo(Array array, int index) + { + ((ICollection) _list).CopyTo(array, index); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _list.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _list.GetEnumerator(); + } + + int IList.IndexOf(DisposableClass item) + { + return _list.IndexOf(item); + } + + int IList.IndexOf(object value) + { + return ((IList) _list).IndexOf(value); + } + + void IList.Insert(int index, DisposableClass item) + { + _list.Insert(index, item); + } + + void IList.Insert(int index, object value) + { + ((IList) _list).Insert(index, value); + } + + bool ICollection.Remove(DisposableClass item) + { + return _list.Remove(item); + } + + void IList.Remove(object value) + { + ((IList) _list).Remove(value); + } + + void IList.RemoveAt(int index) + { + _list.RemoveAt(index); + } + + void IList.RemoveAt(int index) + { + _list.RemoveAt(index); + } + } + + public sealed class CustomDictionary2 : IDictionary + { + private readonly Dictionary _dictionary = new Dictionary(); + + int IDictionary.this[string key] { get => _dictionary[key]; set => _dictionary[key] = value; } + + ICollection IDictionary.Keys => _dictionary.Keys; + + ICollection IDictionary.Values => _dictionary.Values; + + int ICollection>.Count => _dictionary.Count; + + bool ICollection>.IsReadOnly => false; + + void IDictionary.Add(string key, int value) + { + _dictionary.Add(key, value); + } + + void ICollection>.Add(KeyValuePair item) + { + ((ICollection>) _dictionary).Add(item); + } + + void ICollection>.Clear() + { + _dictionary.Clear(); + } + + bool ICollection>.Contains(KeyValuePair item) + { + return _dictionary.Contains(item); + } + + bool IDictionary.ContainsKey(string key) + { + return _dictionary.ContainsKey(key); + } + + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + { + ((ICollection>) _dictionary).CopyTo(array, arrayIndex); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return _dictionary.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _dictionary.GetEnumerator(); + } + + bool IDictionary.Remove(string key) + { + return _dictionary.Remove(key); + } + + bool ICollection>.Remove(KeyValuePair item) + { + return ((ICollection>) _dictionary).Remove(item); + } + + bool IDictionary.TryGetValue(string key, out int value) + { + return _dictionary.TryGetValue(key, out value); + } + } } \ No newline at end of file diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index a8e449091..4aeeeabc4 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -159,6 +159,11 @@ namespace cswinrt w.write(to_csharp_type(type)); } + void write_fundamental_non_projected_type(writer& w, fundamental_type type) + { + w.write(to_dotnet_type(type)); + } + void write_projection_type(writer& w, type_semantics const& semantics); void write_projection_type_for_name_type(writer& w, type_semantics const& semantics, typedef_name_type const& nameType); @@ -200,6 +205,13 @@ namespace cswinrt bool authoredType = settings.component && settings.filter.includes(type); auto typeNamespace = type.TypeNamespace(); auto typeName = type.TypeName(); + + if (nameType == typedef_name_type::NonProjected) + { + w.write("%.%", typeNamespace, typeName); + return; + } + if (auto proj = get_mapped_type(typeNamespace, typeName)) { typeNamespace = proj->mapped_namespace; @@ -313,7 +325,17 @@ namespace cswinrt bind_list(", ", type.generic_args, nameType)); }, [&](generic_type_param const& param) { w.write(param.Name()); }, - [&](fundamental_type const& type) { write_fundamental_type(w, type); }); + [&](fundamental_type const& type) + { + if (nameType == typedef_name_type::NonProjected) + { + write_fundamental_non_projected_type(w, type); + } + else + { + write_fundamental_type(w, type); + } + }); } void write_projection_type(writer& w, type_semantics const& semantics) @@ -816,7 +838,7 @@ namespace cswinrt % %.%(%) => %.%(%); )", return_type, - bind(method_interface, typedef_name_type::Projected, false), + bind(method_interface, typedef_name_type::CCW, false), method.Name(), bind_list(", ", signature.params()), method_target, @@ -825,7 +847,7 @@ namespace cswinrt ); } - auto method_signature_equal(MethodDef const& first, MethodDef const& second) + auto method_signature_equal(writer& w, MethodDef const& first, MethodDef const& second) { method_signature signature_first{ first }; method_signature signature_second{ second }; @@ -835,34 +857,39 @@ namespace cswinrt return false; } - writer first_method_return_type, second_method_return_type; - write_projection_return_type(first_method_return_type, signature_first); - write_projection_return_type(second_method_return_type, signature_second); - if (first_method_return_type.flush_to_string() != second_method_return_type.flush_to_string()) + auto first_method_return_type = w.write_temp("%", bind(signature_first)); + auto second_method_return_type = w.write_temp("%", bind(signature_second)); + if (first_method_return_type != second_method_return_type) { return false; } - writer first_method_parameters, second_method_parameters; - bind_list(", ", signature_first.params())(first_method_parameters); - bind_list(", ", signature_second.params())(second_method_parameters); + auto first_method_parameters = w.write_temp("%", bind_list(", ", signature_first.params())); + auto second_method_parameters = w.write_temp("%", bind_list(", ", signature_second.params())); + return first_method_parameters == second_method_parameters; + } - return first_method_parameters.flush_to_string() == second_method_parameters.flush_to_string(); + void write_non_projected_type(writer& w, TypeDef const& type) + { + writer::write_generic_type_name_guard g(w, [&](writer& w, uint32_t index) + { + write_projection_type_for_name_type(w, w.get_generic_arg_scope(index).first, typedef_name_type::NonProjected); + }); + + w.write("%", bind(type, typedef_name_type::NonProjected, false)); } - auto is_implemented_as_private_method(TypeDef const& class_type, MethodDef const& interface_method) + auto is_implemented_as_private_method(writer& w, TypeDef const& class_type, MethodDef const& interface_method) { - writer writer; - auto interface_method_name = writer.write_temp( - "%.%.%", - interface_method.Parent().TypeNamespace(), - interface_method.Parent().TypeName(), + auto interface_method_name = w.write_temp( + "%.%", + bind(interface_method.Parent()), interface_method.Name()); for (auto&& class_method : class_type.MethodList()) { if (class_method.Flags().Access() == MemberAccess::Private && class_method.Name() == interface_method_name && - method_signature_equal(class_method, interface_method)) + method_signature_equal(w, class_method, interface_method)) { return true; } @@ -871,6 +898,30 @@ namespace cswinrt return false; } + auto is_implemented_as_private_mapped_interface(writer& w, TypeDef const& class_type, TypeDef const& interface_type) + { + // Assume as long as one member of the custom mapped interface is implemented as a private member, + // that the entire interface is implemented as an explicit implementation. + if (size(interface_type.MethodList()) != 0) + { + return is_implemented_as_private_method(w, class_type, interface_type.MethodList().first); + } + + if (size(interface_type.PropertyList()) != 0) + { + auto [getter, _] = get_property_methods(interface_type.PropertyList().first); + return is_implemented_as_private_method(w, class_type, getter); + } + + if (size(interface_type.EventList()) != 0) + { + auto [add, _] = get_event_methods(interface_type.EventList().first); + return is_implemented_as_private_method(w, class_type, add); + } + + return false; + } + void write_class_method(writer& w, MethodDef const& method, TypeDef const& class_type, bool is_overridable, bool is_protected, std::string_view interface_member, std::string_view platform_attribute) { @@ -917,7 +968,7 @@ namespace cswinrt } } - bool is_private = is_implemented_as_private_method(class_type, method); + bool is_private = is_implemented_as_private_method(w, class_type, method); if (!is_private) { write_method(w, signature, method.Name(), return_type, interface_member, access_spec, method_spec, platform_attribute); @@ -1046,7 +1097,7 @@ namespace cswinrt std::string write_explicit_name(writer& w, TypeDef const& iface, std::string_view name) { - return w.write_temp("%.%", write_type_name_temp(w, iface), name); + return w.write_temp("%.%", write_type_name_temp(w, iface, "%", typedef_name_type::CCW), name); } std::string write_prop_type(writer& w, Property const& prop) @@ -1114,7 +1165,7 @@ remove => %.% -= value; } auto [add, _] = get_event_methods(event); - bool is_private = is_implemented_as_private_method(class_type, add); + bool is_private = is_implemented_as_private_method(w, class_type, add); if (!is_private) { write_event(w, event.Name(), event, interface_member, visibility, ""sv, platform_attribute); @@ -1727,18 +1778,18 @@ MarshalInspectable.DisposeAbi(ptr); write_method(w, signature, method.Name(), return_type, method_target, "public "sv, factory_class ? ""sv : "static "sv, platform_attribute); } - void write_static_property(writer& w, Property const& prop, std::string_view prop_target, std::string_view platform_attribute = ""sv) + void write_static_property(writer& w, Property const& prop, std::string_view prop_target, bool factory_class = false, std::string_view platform_attribute = ""sv) { auto [getter, setter] = get_property_methods(prop); auto getter_target = getter ? prop_target : ""; auto setter_target = setter ? prop_target : ""; write_property(w, prop.Name(), prop.Name(), write_prop_type(w, prop), - getter_target, setter_target, "public "sv, "static "sv, platform_attribute, platform_attribute); + getter_target, setter_target, "public "sv, factory_class ? ""sv : "static "sv, platform_attribute, platform_attribute); } - void write_static_event(writer& w, Event const& event, std::string_view event_target, std::string_view platform_attribute = ""sv) + void write_static_event(writer& w, Event const& event, std::string_view event_target, bool factory_class = false, std::string_view platform_attribute = ""sv) { - write_event(w, event.Name(), event, event_target, "public "sv, "static "sv, platform_attribute); + write_event(w, event.Name(), event, event_target, "public "sv, factory_class ? ""sv : "static "sv, platform_attribute); } void write_static_members(writer& w, TypeDef const& static_type, TypeDef const& class_type) @@ -1746,8 +1797,8 @@ MarshalInspectable.DisposeAbi(ptr); auto cache_object = write_static_cache_object(w, static_type.TypeName(), class_type); auto platform_attribute = write_platform_attribute_temp(w, static_type); w.write_each(static_type.MethodList(), cache_object, false, platform_attribute); - w.write_each(static_type.PropertyList(), cache_object, platform_attribute); - w.write_each(static_type.EventList(), cache_object, platform_attribute); + w.write_each(static_type.PropertyList(), cache_object, false, platform_attribute); + w.write_each(static_type.EventList(), cache_object, false, platform_attribute); } void write_attributed_types(writer& w, TypeDef const& type) @@ -1827,9 +1878,19 @@ IEnumerator IEnumerable.GetEnumerator() => %.GetEnumerator(); visibility, element, self, target); if (!include_nongeneric) return; - w.write(R"( + + if (emit_explicit) + { + w.write(R"( +IEnumerator IEnumerable.GetEnumerator() => %.GetEnumerator(); +)", target); + } + else + { + w.write(R"( IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); )"); + } } void write_enumerator_members(writer& w, std::string_view target, bool emit_explicit) @@ -2064,53 +2125,51 @@ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); visibility, self, target); } - void write_notify_data_error_info_members(writer& w, std::string_view target) + void write_notify_data_error_info_members(writer& w, std::string_view target, bool emit_explicit) { + auto self = emit_explicit ? "global::System.ComponentModel.INotifyDataErrorInfo." : ""; + auto visibility = emit_explicit ? "" : "public "; + w.write(R"( -public global::System.Collections.IEnumerable GetErrors(string propertyName) => %.GetErrors(propertyName); +%global::System.Collections.IEnumerable %GetErrors(string propertyName) => %.GetErrors(propertyName); -global::System.Collections.IEnumerable global::System.ComponentModel.INotifyDataErrorInfo.GetErrors(string propertyName) => GetErrors(propertyName); -public event global::System.EventHandler ErrorsChanged +%event global::System.EventHandler %ErrorsChanged { add => %.ErrorsChanged += value; remove => %.ErrorsChanged -= value; } - -event global::System.EventHandler global::System.ComponentModel.INotifyDataErrorInfo.ErrorsChanged -{ -add => this.ErrorsChanged += value; -remove => this.ErrorsChanged -= value; -} -public bool HasErrors => %.HasErrors; -bool global::System.ComponentModel.INotifyDataErrorInfo.HasErrors {get => HasErrors; } -)", target, target, target, target); +%bool %HasErrors {get => %.HasErrors; } +)", + visibility, self, target, + visibility, self, target, target, + visibility, self, target); } - void write_custom_mapped_type_members(writer& w, std::string_view target, mapped_type const& mapping) + void write_custom_mapped_type_members(writer& w, std::string_view target, mapped_type const& mapping, bool is_private) { if (mapping.abi_name == "IIterable`1") { - write_enumerable_members(w, target, true, false); + write_enumerable_members(w, target, true, is_private); } else if (mapping.abi_name == "IIterator`1") { - write_enumerator_members(w, target, false); + write_enumerator_members(w, target, is_private); } else if (mapping.abi_name == "IMapView`2") { - write_readonlydictionary_members(w, target, false, false); + write_readonlydictionary_members(w, target, false, is_private); } else if (mapping.abi_name == "IMap`2") { - write_dictionary_members(w, target, false, false); + write_dictionary_members(w, target, false, is_private); } else if (mapping.abi_name == "IVectorView`1") { - write_readonlylist_members(w, target, false, false); + write_readonlylist_members(w, target, false, is_private); } else if (mapping.abi_name == "IVector`1") { - write_list_members(w, target, false, false); + write_list_members(w, target, false, is_private); } else if (mapping.mapped_namespace == "System.Collections" && mapping.mapped_name == "IEnumerable") { @@ -2118,15 +2177,15 @@ bool global::System.ComponentModel.INotifyDataErrorInfo.HasErrors {get => HasErr } else if (mapping.mapped_namespace == "System.Collections" && mapping.mapped_name == "IList") { - write_nongeneric_list_members(w, target, false, false); + write_nongeneric_list_members(w, target, false, is_private); } else if (mapping.mapped_namespace == "System" && mapping.mapped_name == "IDisposable") { - write_idisposable_members(w, target, false); + write_idisposable_members(w, target, is_private); } else if (mapping.mapped_namespace == "System.ComponentModel" && mapping.mapped_name == "INotifyDataErrorInfo") { - write_notify_data_error_info_members(w, target); + write_notify_data_error_info_members(w, target, is_private); } } @@ -2225,7 +2284,8 @@ private % AsInternal(InterfaceTag<%> _) => ((Lazy<%>)_lazyInterfaces[typeof(%)] if(auto mapping = get_mapped_type(interface_type.TypeNamespace(), interface_type.TypeName()); mapping && mapping->has_custom_members_output) { - write_custom_mapped_type_members(w, target, *mapping); + bool is_private = is_implemented_as_private_mapped_interface(w, type, interface_type); + write_custom_mapped_type_members(w, target, *mapping, is_private); return; } @@ -2242,7 +2302,7 @@ private % AsInternal(InterfaceTag<%> _) => ((Lazy<%>)_lazyInterfaces[typeof(%)] MethodDef getter, setter; std::tie(getter, setter) = get_property_methods(prop); auto prop_type = write_prop_type(w, prop); - auto is_private = getter && is_implemented_as_private_method(type, getter); // for explicitly implemented interfaces, assume there is always a get. + auto is_private = getter && is_implemented_as_private_method(w, type, getter); // for explicitly implemented interfaces, assume there is always a get. auto property_name = is_private ? w.write_temp("%.%", interface_name, prop.Name()) : std::string(prop.Name()); auto [prop_targets, inserted] = properties.try_emplace(property_name, prop_type, @@ -6158,6 +6218,8 @@ bind_list(", ", signature.params()) else if (factory.statics) { w.write_each(factory.type.MethodList(), projected_type_name, true, ""sv); + w.write_each(factory.type.PropertyList(), projected_type_name, true, ""sv); + w.write_each(factory.type.EventList(), projected_type_name, true, ""sv); } } } diff --git a/src/cswinrt/helpers.h b/src/cswinrt/helpers.h index 213011ed9..04c2a262b 100644 --- a/src/cswinrt/helpers.h +++ b/src/cswinrt/helpers.h @@ -891,7 +891,8 @@ namespace cswinrt { Projected, CCW, - ABI + ABI, + NonProjected }; std::string get_mapped_element_type(ElementType elementType)