Browse Source

Optimize the pass for properties

Signed-off-by: Dimitar Dobrev <dpldobrev@protonmail.com>
pull/1261/head
Dimitar Dobrev 7 years ago
parent
commit
914b977dfd
  1. 562
      src/Generator/Passes/GetterSetterToPropertyPass.cs
  2. 12
      src/Generator/Passes/MultipleInheritancePass.cs
  3. 2
      src/Generator/Passes/SpecializationMethodsWithDependentPointersPass.cs
  4. 2
      tests/CSharp/CSharp.Tests.cs
  5. 4
      tests/Common/Common.Tests.cs

562
src/Generator/Passes/GetterSetterToPropertyPass.cs

@ -13,363 +13,345 @@ namespace CppSharp.Passes
{ {
public class GetterSetterToPropertyPass : TranslationUnitPass public class GetterSetterToPropertyPass : TranslationUnitPass
{ {
private class PropertyGenerator static GetterSetterToPropertyPass()
{ {
private readonly List<Method> getters = new List<Method>(); LoadVerbs();
private readonly List<Method> setters = new List<Method>(); }
private readonly List<Method> setMethods = new List<Method>();
private readonly List<Method> nonSetters = new List<Method>();
private bool useHeuristics = true;
public PropertyGenerator(Class @class, bool useHeuristics) private static void LoadVerbs()
{
var assembly = Assembly.GetAssembly(typeof(GetterSetterToPropertyPass));
using (var resourceStream = GetResourceStream(assembly))
{ {
this.useHeuristics = useHeuristics; using (var streamReader = new StreamReader(resourceStream))
foreach (var method in @class.Methods.Where( while (!streamReader.EndOfStream)
m => !m.IsConstructor && !m.IsDestructor && !m.IsOperator && m.IsGenerated && verbs.Add(streamReader.ReadLine());
!m.ExcludeFromPasses.Contains(typeof(GetterSetterToPropertyPass))))
DistributeMethod(method);
} }
}
public void GenerateProperties() private static Stream GetResourceStream(Assembly assembly)
{ {
GenerateProperties(setters, false); var resources = assembly.GetManifestResourceNames();
GenerateProperties(setMethods, true);
if (resources.Count() == 0)
foreach (Method getter in throw new Exception("Cannot find embedded verbs data resource.");
from getter in getters
where getter.IsGenerated && // We are relying on this fact that there is only one resource embedded.
getter.SynthKind != FunctionSynthKind.ComplementOperator && // Before we loaded the resource by name but found out that naming was
((Class) getter.Namespace).Methods.All( // different between different platforms and/or build systems.
m => m == getter || !m.IsGenerated || m.Name != getter.Name || return assembly.GetManifestResourceStream(resources[0]);
m.Parameters.Count(p => p.Kind == ParameterKind.Regular) == 0) }
select getter)
{ public GetterSetterToPropertyPass()
// Make it a read-only property {
GenerateProperty(getter.Namespace, getter); VisitOptions.VisitClassBases = false;
} VisitOptions.VisitClassFields = false;
} VisitOptions.VisitClassProperties = false;
VisitOptions.VisitClassMethods = false;
VisitOptions.VisitNamespaceEnums = false;
VisitOptions.VisitNamespaceTemplates = false;
VisitOptions.VisitNamespaceTypedefs = false;
VisitOptions.VisitNamespaceEvents = false;
VisitOptions.VisitNamespaceVariables = false;
VisitOptions.VisitFunctionParameters = false;
VisitOptions.VisitTemplateArguments = false;
}
private void GenerateProperties(IEnumerable<Method> settersToUse, bool readOnly) public override bool VisitClassDecl(Class @class)
{
if (!base.VisitClassDecl(@class))
return false;
ProcessProperties(@class, GenerateProperties(@class));
return false;
}
protected virtual HashSet<Property> GenerateProperties(Class @class)
{
var newProperties = new HashSet<Property>();
foreach (var method in @class.Methods.Where(
m => !m.IsConstructor && !m.IsDestructor && !m.IsOperator && m.IsGenerated &&
m.SynthKind != FunctionSynthKind.DefaultValueOverload &&
m.SynthKind != FunctionSynthKind.ComplementOperator &&
!m.ExcludeFromPasses.Contains(typeof(GetterSetterToPropertyPass))))
{ {
foreach (var setter in settersToUse) if (IsGetter(method))
{ {
var type = (Class) setter.Namespace; string name = GetPropertyName(method.Name);
var firstWord = GetFirstWord(setter.Name); QualifiedType type = method.OriginalReturnType;
string property; Property property = GetProperty(method, name, type);
if ((firstWord == "set" || firstWord == "set_") && if (property.GetMethod == null)
firstWord.Length < setter.Name.Length)
property = setter.Name.Substring(firstWord.Length);
else
property = setter.Name;
var nameBuilder = new StringBuilder(property);
if (char.IsLower(setter.Name[0]))
nameBuilder[0] = char.ToLowerInvariant(nameBuilder[0]);
string afterSet = nameBuilder.ToString();
var s = setter;
foreach (var getter in nonSetters.Where(m => m.Namespace == type &&
m.ExplicitInterfaceImpl == s.ExplicitInterfaceImpl))
{ {
var name = GetReadWritePropertyName(getter, afterSet); property.GetMethod = method;
if (name == afterSet && property.QualifiedType = method.OriginalReturnType;
GetUnderlyingType(getter.OriginalReturnType).Equals( newProperties.Add(property);
GetUnderlyingType(setter.Parameters[0].QualifiedType)))
{
Method g = getter;
foreach (var method in type.Methods.Where(m => m != g && m.Name == name))
{
var oldName = method.Name;
method.Name = string.Format("get{0}{1}",
char.ToUpperInvariant(method.Name[0]), method.Name.Substring(1));
Diagnostics.Debug("Method {0}::{1} renamed to {2}", method.Namespace.Name, oldName, method.Name);
}
foreach (var @event in type.Events.Where(e => e.Name == name))
{
var oldName = @event.Name;
@event.Name = string.Format("on{0}{1}",
char.ToUpperInvariant(@event.Name[0]), @event.Name.Substring(1));
Diagnostics.Debug("Event {0}::{1} renamed to {2}", @event.Namespace.Name, oldName, @event.Name);
}
GenerateProperty(name, getter.Namespace, getter, readOnly ? null : setter);
goto next;
}
} }
Property baseProperty = type.GetBaseProperty(new Property { Name = afterSet }, getTopmost: true); else
if (!type.IsInterface && baseProperty != null && baseProperty.IsVirtual && setter.IsVirtual) method.GenerationKind = GenerationKind.Generate;
{ continue;
bool isReadOnly = baseProperty.SetMethod == null;
var name = GetReadWritePropertyName(baseProperty.GetMethod, afterSet);
GenerateProperty(name, setter.Namespace, baseProperty.GetMethod,
readOnly || isReadOnly ? null : setter);
}
next:
;
} }
foreach (Method nonSetter in nonSetters) if (IsSetter(method))
{ {
Class type = (Class) nonSetter.Namespace; string name = GetPropertyNameFromSetter(method.Name);
string name = GetPropertyName(nonSetter.Name); QualifiedType type = method.Parameters.First(p => p.Kind == ParameterKind.Regular).QualifiedType;
Property baseProperty = type.GetBaseProperty(new Property { Name = name }, getTopmost: true); Property property = GetProperty(method, name, type);
if (!type.IsInterface && baseProperty != null && baseProperty.IsVirtual) property.SetMethod = method;
{ newProperties.Add(property);
bool isReadOnly = baseProperty.SetMethod == null;
if (readOnly == isReadOnly)
{
GenerateProperty(nonSetter.Namespace, nonSetter,
readOnly ? null : baseProperty.SetMethod);
}
}
} }
} }
private static string GetReadWritePropertyName(INamedDecl getter, string afterSet) return newProperties;
{ }
string name = GetPropertyName(getter.Name);
if (name != afterSet && name.StartsWith("is", StringComparison.Ordinal) && private static Property GetProperty(Method method, string name, QualifiedType type)
name != "is") {
{ Type underlyingType = GetUnderlyingType(type);
name = char.ToLowerInvariant(name[2]) + name.Substring(3); Class @class = (Class) method.Namespace;
} Property property = @class.Properties.Find(
return name; p => p.Field == null &&
} (p.Name == name ||
(p.GetMethod != null && GetReadWritePropertyName(p.GetMethod, name) == name)) &&
((p.GetMethod != null &&
GetUnderlyingType(p.GetMethod.OriginalReturnType).Equals(underlyingType)) ||
(p.SetMethod != null &&
GetUnderlyingType(p.SetMethod.Parameters[0].QualifiedType).Equals(underlyingType)))) ??
new Property { Name = name, QualifiedType = type };
private static Type GetUnderlyingType(QualifiedType type) if (property.Namespace == null)
{ {
TagType tagType = type.Type as TagType; property.Namespace = method.Namespace;
if (tagType != null) property.Access = method.Access;
return type.Type; @class.Properties.Add(property);
// TODO: we should normally check pointer types for const;
// however, there's some bug, probably in the parser, that returns IsConst = false for "const Type& arg"
// so skip the check for the time being
PointerType pointerType = type.Type as PointerType;
return pointerType != null ? pointerType.Pointee : type.Type;
} }
else
private static void GenerateProperty(DeclarationContext context, Method getter, Method setter = null)
{ {
GenerateProperty(GetPropertyName(getter.Name), context, getter, setter); property.Access = (AccessSpecifier) Math.Max(
(int) (property.GetMethod ?? property.SetMethod).Access,
(int) method.Access);
} }
private static void GenerateProperty(string name, DeclarationContext context, Method getter, Method setter) property.Name = property.OriginalName = name;
{ method.GenerationKind = GenerationKind.Internal;
var type = (Class) context; if (method.ExplicitInterfaceImpl != null)
if (type.Properties.Any(p => p.Name == name && property.ExplicitInterfaceImpl = method.ExplicitInterfaceImpl;
p.ExplicitInterfaceImpl == getter.ExplicitInterfaceImpl)) return property;
return; }
var property = new Property private static void ProcessProperties(Class @class, HashSet<Property> newProperties)
{ {
Access = getter.Access == AccessSpecifier.Public || foreach (var property in newProperties)
(setter != null && setter.Access == AccessSpecifier.Public) ? {
AccessSpecifier.Public : AccessSpecifier.Protected, if (property.IsOverride)
Name = name,
Namespace = type,
QualifiedType = getter.OriginalReturnType,
OriginalNamespace = getter.OriginalNamespace
};
if (getter.IsOverride || (setter != null && setter.IsOverride))
{ {
var baseVirtualProperty = type.GetBaseProperty(property, getTopmost: true); Property baseProperty = GetBaseProperty(@class, property);
if (baseVirtualProperty != null && !baseVirtualProperty.IsVirtual) if (baseProperty == null)
{ {
// the only way the above can happen is if we are generating properties in abstract implementations if (property.SetMethod != null)
// in which case we can have less naming conflicts since the abstract base can also contain non-virtual properties {
if (getter.SynthKind == FunctionSynthKind.AbstractImplCall) property.SetMethod.GenerationKind = GenerationKind.Generate;
return; property.SetMethod = null;
throw new Exception(string.Format( }
"Base of property {0} is not virtual while the getter is.", else
getter.QualifiedOriginalName)); {
property.GetMethod.GenerationKind = GenerationKind.Generate;
property.GetMethod = null;
}
} }
if (baseVirtualProperty == null || baseVirtualProperty.SetMethod == null) else if (property.GetMethod == null && baseProperty.SetMethod != null)
setter = null; property.GetMethod = baseProperty.GetMethod;
} else if (property.SetMethod == null)
property.GetMethod = getter; property.SetMethod = baseProperty.SetMethod;
property.SetMethod = setter;
property.ExplicitInterfaceImpl = getter.ExplicitInterfaceImpl;
if (property.ExplicitInterfaceImpl == null && setter != null)
{
property.ExplicitInterfaceImpl = setter.ExplicitInterfaceImpl;
} }
if (getter.Comment != null) if (property.GetMethod == null)
{ {
property.Comment = CombineComments(getter, setter); if (property.SetMethod != null)
property.SetMethod.GenerationKind = GenerationKind.Generate;
@class.Properties.Remove(property);
continue;
} }
type.Properties.Add(property);
getter.GenerationKind = GenerationKind.Internal;
if (setter != null)
setter.GenerationKind = GenerationKind.Internal;
}
private static RawComment CombineComments(Declaration getter, Declaration setter) foreach (var method in @class.Methods.Where(
{ m => m.IsGenerated && m.Name == property.Name))
var comment = new RawComment
{
Kind = getter.Comment.Kind,
BriefText = getter.Comment.BriefText,
Text = getter.Comment.Text
};
if (getter.Comment.FullComment != null)
{ {
comment.FullComment = new FullComment(); var oldName = method.Name;
comment.FullComment.Blocks.AddRange(getter.Comment.FullComment.Blocks); method.Name = $@"get{char.ToUpperInvariant(method.Name[0])}{
if (getter != setter && setter != null && setter.Comment != null) method.Name.Substring(1)}";
{ Diagnostics.Debug("Method {0}::{1} renamed to {2}",
comment.BriefText += Environment.NewLine + setter.Comment.BriefText; method.Namespace.Name, oldName, method.Name);
comment.Text += Environment.NewLine + setter.Comment.Text;
comment.FullComment.Blocks.AddRange(setter.Comment.FullComment.Blocks);
}
} }
return comment; foreach (var @event in @class.Events.Where(
} e => e.Name == property.Name))
private static string GetPropertyName(string name)
{
var firstWord = GetFirstWord(name);
if (Match(firstWord, new[] { "get" }) && name != firstWord &&
!char.IsNumber(name[3]))
{ {
if (char.IsLower(name[0])) var oldName = @event.Name;
{ @event.Name = $@"on{char.ToUpperInvariant(@event.Name[0])}{
if (name.Length == 4) @event.Name.Substring(1)}";
{ Diagnostics.Debug("Event {0}::{1} renamed to {2}",
return char.ToLowerInvariant( @event.Namespace.Name, oldName, @event.Name);
name[3]).ToString(CultureInfo.InvariantCulture);
}
return char.ToLowerInvariant(
name[3]).ToString(CultureInfo.InvariantCulture) +
name.Substring(4);
}
return name.Substring(3);
} }
return name; CombineComments(property);
} }
}
private static string GetPropertyNameFromSetter(Method setter) private static Property GetBaseProperty(Class @class, Property @override)
{
foreach (var @base in @class.Bases)
{ {
var name = setter.Name.Substring("set".Length); Class baseClass = @base.Class.OriginalClass ?? @base.Class;
if (string.IsNullOrEmpty(name)) Property baseProperty = baseClass.Properties.Find(p =>
return name; (@override.GetMethod != null && @override.GetMethod.BaseMethod == p.GetMethod) ||
if (char.IsLower(setter.Name[0]) && !char.IsLower(name[0])) (@override.SetMethod != null && @override.SetMethod.BaseMethod == p.SetMethod) ||
return char.ToLowerInvariant(name[0]) + name.Substring(1); (@override.Field != null && @override.Field == p.Field));
return name; if (baseProperty != null)
} return baseProperty;
private void DistributeMethod(Method method) baseProperty = GetBaseProperty(@base.Class, @override);
{ if (baseProperty != null)
Type returnType = method.OriginalReturnType.Type.Desugar(); return baseProperty;
if ((returnType.IsPrimitiveType(PrimitiveType.Void) ||
returnType.IsPrimitiveType(PrimitiveType.Bool)) &&
method.Parameters.Any(p => p.Kind == ParameterKind.Regular))
{
if (method.Parameters.Count == 1)
setters.Add(method);
else if (method.Parameters.Count > 1)
setMethods.Add(method);
}
else
{
if (method.ConvertToProperty || IsGetter(method))
getters.Add(method);
if (method.Parameters.All(p => p.Kind == ParameterKind.IndirectReturnType))
nonSetters.Add(method);
}
} }
return null;
}
private bool IsGetter(Method method) private static string GetReadWritePropertyName(INamedDecl getter, string afterSet)
{
string name = GetPropertyName(getter.Name);
if (name != afterSet && name.StartsWith("is", StringComparison.Ordinal) &&
name != "is")
{ {
if (method.IsDestructor || name = char.ToLowerInvariant(name[2]) + name.Substring(3);
(method.OriginalReturnType.Type.IsPrimitiveType(PrimitiveType.Void)) || }
method.Parameters.Any(p => p.Kind != ParameterKind.IndirectReturnType)) return name;
return false; }
var firstWord = GetFirstWord(method.Name);
if (firstWord.Length < method.Name.Length && Match(firstWord, new[] {"get", "is", "has"}))
return true;
if (useHeuristics && !Match(firstWord, new[] {"to", "new"}) && !verbs.Contains(firstWord)) private static Type GetUnderlyingType(QualifiedType type)
return true; {
TagType tagType = type.Type as TagType;
if (tagType != null)
return type.Type;
// TODO: we should normally check pointer types for const;
// however, there's some bug, probably in the parser, that returns IsConst = false for "const Type& arg"
// so skip the check for the time being
PointerType pointerType = type.Type as PointerType;
return pointerType != null ? pointerType.Pointee : type.Type;
}
return false; private static void CombineComments(Property property)
} {
Method getter = property.GetMethod;
if (getter.Comment == null)
return;
private static bool Match(string prefix, IEnumerable<string> prefixes) var comment = new RawComment
{
Kind = getter.Comment.Kind,
BriefText = getter.Comment.BriefText,
Text = getter.Comment.Text
};
if (getter.Comment.FullComment != null)
{ {
return prefixes.Any(p => prefix == p || prefix == p + '_'); comment.FullComment = new FullComment();
comment.FullComment.Blocks.AddRange(getter.Comment.FullComment.Blocks);
Method setter = property.SetMethod;
if (getter != setter && setter?.Comment != null)
{
comment.BriefText += Environment.NewLine + setter.Comment.BriefText;
comment.Text += Environment.NewLine + setter.Comment.Text;
comment.FullComment.Blocks.AddRange(setter.Comment.FullComment.Blocks);
}
} }
property.Comment = comment;
}
private static string GetFirstWord(string name) private static string GetPropertyName(string name)
{
var firstWord = GetFirstWord(name);
if (Match(firstWord, new[] { "get" }) && name != firstWord &&
!char.IsNumber(name[3]))
{ {
var firstWord = new List<char> { char.ToLowerInvariant(name[0]) }; if (char.IsLower(name[0]))
for (int i = 1; i < name.Length; i++)
{ {
var c = name[i]; if (name.Length == 4)
if (char.IsLower(c))
{ {
firstWord.Add(c); return char.ToLowerInvariant(
continue; name[3]).ToString(CultureInfo.InvariantCulture);
}
if (c == '_')
{
firstWord.Add(c);
break;
} }
if (char.IsUpper(c)) return char.ToLowerInvariant(
break; name[3]).ToString(CultureInfo.InvariantCulture) +
name.Substring(4);
} }
return new string(firstWord.ToArray()); return name.Substring(3);
} }
return name;
} }
private static readonly HashSet<string> verbs = new HashSet<string>(); private static string GetPropertyNameFromSetter(string name)
static GetterSetterToPropertyPass()
{ {
LoadVerbs(); var nameBuilder = new StringBuilder(name);
} string firstWord = GetFirstWord(name);
if (firstWord == "set" || firstWord == "set_")
nameBuilder.Remove(0, firstWord.Length);
if (nameBuilder.Length == 0)
return nameBuilder.ToString();
private static void LoadVerbs() nameBuilder.TrimUnderscores();
{ if (char.IsLower(name[0]) && !char.IsLower(nameBuilder[0]))
var assembly = Assembly.GetAssembly(typeof(GetterSetterToPropertyPass)); nameBuilder[0] = char.ToLowerInvariant(nameBuilder[0]);
using (var resourceStream = GetResourceStream(assembly)) return nameBuilder.ToString();
{
using (var streamReader = new StreamReader(resourceStream))
while (!streamReader.EndOfStream)
verbs.Add(streamReader.ReadLine());
}
} }
private static Stream GetResourceStream(Assembly assembly) private bool IsGetter(Method method)
{ {
var resources = assembly.GetManifestResourceNames(); if (method.IsDestructor ||
method.OriginalReturnType.Type.IsPrimitiveType(PrimitiveType.Void) ||
method.Parameters.Any(p => p.Kind != ParameterKind.IndirectReturnType))
return false;
var firstWord = GetFirstWord(method.Name);
if (resources.Count() == 0) if (firstWord.Length < method.Name.Length &&
throw new Exception("Cannot find embedded verbs data resource."); Match(firstWord, new[] { "get", "is", "has" }))
return true;
// We are relying on this fact that there is only one resource embedded. if (Options.UsePropertyDetectionHeuristics &&
// Before we loaded the resource by name but found out that naming was !Match(firstWord, new[] { "to", "new" }) && !verbs.Contains(firstWord))
// different between different platforms and/or build systems. return true;
return assembly.GetManifestResourceStream(resources[0]);
return false;
} }
public GetterSetterToPropertyPass() private static bool IsSetter(Method method)
{ {
VisitOptions.VisitClassBases = false; Type returnType = method.OriginalReturnType.Type.Desugar();
VisitOptions.VisitClassFields = false; return (returnType.IsPrimitiveType(PrimitiveType.Void) ||
VisitOptions.VisitClassProperties = false; returnType.IsPrimitiveType(PrimitiveType.Bool)) &&
VisitOptions.VisitClassMethods = false; method.Parameters.Count(p => p.Kind == ParameterKind.Regular) == 1;
VisitOptions.VisitNamespaceEnums = false;
VisitOptions.VisitNamespaceTemplates = false;
VisitOptions.VisitNamespaceTypedefs = false;
VisitOptions.VisitNamespaceEvents = false;
VisitOptions.VisitNamespaceVariables = false;
VisitOptions.VisitFunctionParameters = false;
VisitOptions.VisitTemplateArguments = false;
} }
public override bool VisitClassDecl(Class @class) private static bool Match(string prefix, IEnumerable<string> prefixes)
{ {
if (base.VisitClassDecl(@class)) return prefixes.Any(p => prefix == p || prefix == p + '_');
new PropertyGenerator(@class, Options.UsePropertyDetectionHeuristics).GenerateProperties();
return false;
} }
private static string GetFirstWord(string name)
{
var firstWord = new List<char> { char.ToLowerInvariant(name[0]) };
for (int i = 1; i < name.Length; i++)
{
var c = name[i];
if (char.IsLower(c))
{
firstWord.Add(c);
continue;
}
if (c == '_')
{
firstWord.Add(c);
break;
}
if (char.IsUpper(c))
break;
}
return new string(firstWord.ToArray());
}
private static readonly HashSet<string> verbs = new HashSet<string>();
} }
} }

12
src/Generator/Passes/MultipleInheritancePass.cs

@ -125,6 +125,7 @@ namespace CppSharp.Passes
QualifiedType = new QualifiedType(new BuiltinType(PrimitiveType.IntPtr)), QualifiedType = new QualifiedType(new BuiltinType(PrimitiveType.IntPtr)),
GetMethod = new Method GetMethod = new Method
{ {
Name = Helpers.InstanceIdentifier,
SynthKind = FunctionSynthKind.InterfaceInstance, SynthKind = FunctionSynthKind.InterfaceInstance,
Namespace = @interface Namespace = @interface
} }
@ -147,13 +148,15 @@ namespace CppSharp.Passes
@interface.Declarations.AddRange(@base.Events); @interface.Declarations.AddRange(@base.Events);
var type = new QualifiedType(new BuiltinType(PrimitiveType.IntPtr)); var type = new QualifiedType(new BuiltinType(PrimitiveType.IntPtr));
string pointerAdjustment = "__PointerTo" + @base.Name;
var adjustmentTo = new Property var adjustmentTo = new Property
{ {
Namespace = @interface, Namespace = @interface,
Name = "__PointerTo" + @base.Name, Name = pointerAdjustment,
QualifiedType = type, QualifiedType = type,
GetMethod = new Method GetMethod = new Method
{ {
Name = pointerAdjustment,
SynthKind = FunctionSynthKind.InterfaceInstance, SynthKind = FunctionSynthKind.InterfaceInstance,
Namespace = @interface, Namespace = @interface,
ReturnType = type ReturnType = type
@ -181,12 +184,16 @@ namespace CppSharp.Passes
{ {
var interfaceProperty = new Property(property) { Namespace = @namespace }; var interfaceProperty = new Property(property) { Namespace = @namespace };
if (property.GetMethod != null) if (property.GetMethod != null)
{
interfaceProperty.GetMethod = new Method(property.GetMethod) interfaceProperty.GetMethod = new Method(property.GetMethod)
{ {
OriginalFunction = property.GetMethod, OriginalFunction = property.GetMethod,
Namespace = @namespace Namespace = @namespace
}; };
interfaceProperty.GetMethod.OverriddenMethods.Add(property.GetMethod);
}
if (property.SetMethod != null) if (property.SetMethod != null)
{
// handle indexers // handle indexers
interfaceProperty.SetMethod = property.GetMethod == property.SetMethod ? interfaceProperty.SetMethod = property.GetMethod == property.SetMethod ?
interfaceProperty.GetMethod : new Method(property.SetMethod) interfaceProperty.GetMethod : new Method(property.SetMethod)
@ -194,6 +201,8 @@ namespace CppSharp.Passes
OriginalFunction = property.SetMethod, OriginalFunction = property.SetMethod,
Namespace = @namespace Namespace = @namespace
}; };
interfaceProperty.SetMethod.OverriddenMethods.Add(property.SetMethod);
}
return interfaceProperty; return interfaceProperty;
} }
@ -219,6 +228,7 @@ namespace CppSharp.Passes
OriginalNamespace = @interface, OriginalNamespace = @interface,
OriginalFunction = method.OriginalFunction OriginalFunction = method.OriginalFunction
}; };
impl.OverriddenMethods.Add((Method) method.OriginalFunction);
var rootBaseMethod = @class.GetBaseMethod(method); var rootBaseMethod = @class.GetBaseMethod(method);
if (rootBaseMethod != null && rootBaseMethod.IsDeclared) if (rootBaseMethod != null && rootBaseMethod.IsDeclared)
impl.ExplicitInterfaceImpl = @interface; impl.ExplicitInterfaceImpl = @interface;

2
src/Generator/Passes/SpecializationMethodsWithDependentPointersPass.cs

@ -136,6 +136,8 @@ namespace CppSharp.Passes
} }
} }
specializedMethod.Name = specializedMethod.OriginalName;
extensionMethod.Name = extensionMethod.OriginalName;
extensionMethod.OriginalFunction = specializedMethod; extensionMethod.OriginalFunction = specializedMethod;
extensionMethod.Kind = CXXMethodKind.Normal; extensionMethod.Kind = CXXMethodKind.Normal;
extensionMethod.IsStatic = true; extensionMethod.IsStatic = true;

2
tests/CSharp/CSharp.Tests.cs

@ -1330,7 +1330,7 @@ public unsafe class CSharpTests : GeneratorTestFixture
private class OverrideVirtualTemplate : VirtualTemplate<int> private class OverrideVirtualTemplate : VirtualTemplate<int>
{ {
public override int Function() => 10; public override int Function => 10;
} }
[Test] [Test]

4
tests/Common/Common.Tests.cs

@ -517,8 +517,8 @@ public class CommonTests : GeneratorTestFixture
prop.VirtualSetterReturnsBoolean = 45; prop.VirtualSetterReturnsBoolean = 45;
Assert.That(prop.VirtualSetterReturnsBoolean, Is.EqualTo(45)); Assert.That(prop.VirtualSetterReturnsBoolean, Is.EqualTo(45));
Assert.That(prop.nestedEnum(), Is.EqualTo(5)); Assert.That(prop.nestedEnum, Is.EqualTo(5));
Assert.That(prop.nestedEnum(55), Is.EqualTo(55)); Assert.That(prop.GetNestedEnum(55), Is.EqualTo(55));
Assert.That(prop.Get32Bit, Is.EqualTo(10)); Assert.That(prop.Get32Bit, Is.EqualTo(10));
} }

Loading…
Cancel
Save