mirror of https://github.com/mono/CppSharp.git
17 changed files with 585 additions and 144 deletions
@ -0,0 +1,126 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.AST.Extensions; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.CSharp |
||||||
|
{ |
||||||
|
public static class CSharpSourcesExtensions |
||||||
|
{ |
||||||
|
public static void DisableTypeMap(Class @class, |
||||||
|
List<System.Type> typeMaps, List<string> keys, BindingContext context) |
||||||
|
{ |
||||||
|
var mapped = @class.OriginalClass ?? @class; |
||||||
|
DisableSingleTypeMap(mapped, typeMaps, keys, context); |
||||||
|
if (mapped.IsDependent) |
||||||
|
foreach (var specialization in mapped.Specializations) |
||||||
|
DisableSingleTypeMap(specialization, typeMaps, keys, context); |
||||||
|
} |
||||||
|
|
||||||
|
public static void GenerateNativeConstructorsByValue( |
||||||
|
this CSharpSources gen, Class @class) |
||||||
|
{ |
||||||
|
var printedClass = @class.Visit(gen.TypePrinter); |
||||||
|
var returnType = $"{printedClass}{printedClass.NameSuffix}"; |
||||||
|
if (@class.IsDependent) |
||||||
|
foreach (var specialization in @class.GetSpecializationsToGenerate().Where(s => !s.Ignore)) |
||||||
|
gen.GenerateNativeConstructorByValue(specialization, returnType); |
||||||
|
else |
||||||
|
gen.GenerateNativeConstructorByValue(@class, returnType); |
||||||
|
} |
||||||
|
|
||||||
|
public static void GenerateField(this CSharpSources gen, Class @class, |
||||||
|
Field field, Action<Field, Class> generate, bool isVoid) |
||||||
|
{ |
||||||
|
if (@class.IsDependent) |
||||||
|
{ |
||||||
|
if (@class.Fields.Any(f => f.Type.Desugar() is TemplateParameterType)) |
||||||
|
{ |
||||||
|
foreach (var parameter in @class.TemplateParameters) |
||||||
|
gen.WriteLine("var __{0} = typeof({0});", parameter.Name); |
||||||
|
|
||||||
|
foreach (var specialization in @class.Specializations.Where(s => !s.Ignore)) |
||||||
|
{ |
||||||
|
WriteTemplateSpecializationCheck(gen, @class, specialization); |
||||||
|
gen.WriteStartBraceIndent(); |
||||||
|
var specializedField = specialization.Fields.First( |
||||||
|
f => f.OriginalName == field.OriginalName); |
||||||
|
generate(specializedField, specialization); |
||||||
|
if (isVoid) |
||||||
|
gen.WriteLine("return;"); |
||||||
|
gen.WriteCloseBraceIndent(); |
||||||
|
} |
||||||
|
gen.WriteLine("throw new global::System.InvalidOperationException();"); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
var specialization = @class.Specializations[0]; |
||||||
|
var specializedField = specialization.Fields.First( |
||||||
|
f => f.OriginalName == field.OriginalName); |
||||||
|
generate(specializedField, specialization); |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
generate(field, @class.IsDependent ? @class.Specializations[0] : @class); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void GenerateMember(this CSharpSources gen, |
||||||
|
Class @class, Action<Class> generate, bool isVoid = false) |
||||||
|
{ |
||||||
|
if (@class != null && @class.IsDependent) |
||||||
|
{ |
||||||
|
foreach (var parameter in @class.TemplateParameters) |
||||||
|
gen.WriteLine($"var __{parameter.Name} = typeof({parameter.Name});"); |
||||||
|
|
||||||
|
foreach (var specialization in @class.Specializations.Where(s => !s.Ignore)) |
||||||
|
{ |
||||||
|
WriteTemplateSpecializationCheck(gen, @class, specialization); |
||||||
|
gen.WriteStartBraceIndent(); |
||||||
|
generate(specialization); |
||||||
|
if (isVoid) |
||||||
|
gen.WriteLine("return;"); |
||||||
|
gen.WriteCloseBraceIndent(); |
||||||
|
} |
||||||
|
gen.WriteLine("throw new global::System.InvalidOperationException();"); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
generate(@class); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static void DisableSingleTypeMap(Class mapped, |
||||||
|
List<System.Type> typeMaps, List<string> keys, BindingContext context) |
||||||
|
{ |
||||||
|
var names = new List<string> { mapped.OriginalName }; |
||||||
|
foreach (TypePrintScopeKind kind in Enum.GetValues(typeof(TypePrintScopeKind))) |
||||||
|
{ |
||||||
|
var cppTypePrinter = new CppTypePrinter { PrintScopeKind = kind }; |
||||||
|
names.Add(mapped.Visit(cppTypePrinter)); |
||||||
|
} |
||||||
|
foreach (var name in names) |
||||||
|
{ |
||||||
|
if (context.TypeMaps.TypeMaps.ContainsKey(name)) |
||||||
|
{ |
||||||
|
keys.Add(name); |
||||||
|
typeMaps.Add(context.TypeMaps.TypeMaps[name]); |
||||||
|
context.TypeMaps.TypeMaps.Remove(name); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static void WriteTemplateSpecializationCheck(CSharpSources gen, |
||||||
|
Class @class, ClassTemplateSpecialization specialization) |
||||||
|
{ |
||||||
|
gen.WriteLine("if ({0})", string.Join(" && ", |
||||||
|
Enumerable.Range(0, @class.TemplateParameters.Count).Select( |
||||||
|
i => string.Format("__{0}.IsAssignableFrom(typeof({1}))", |
||||||
|
@class.TemplateParameters[i].Name, |
||||||
|
specialization.Arguments[i].Type.Type.Desugar())))); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,163 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.AST.Extensions; |
||||||
|
|
||||||
|
namespace CppSharp.Passes |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// This pass binds methods of class template specialisations
|
||||||
|
/// which use dependent pointers as parameters or returned types.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>If we have this code:</para>
|
||||||
|
/// <para>template <typename T></para>
|
||||||
|
/// <para>class Template</para>
|
||||||
|
/// <para>{</para>
|
||||||
|
/// <para>public:</para>
|
||||||
|
/// <para> const T* function();</para>
|
||||||
|
/// <para>};</para>
|
||||||
|
/// <para />
|
||||||
|
/// <para>the respective C# wrapper returns just T
|
||||||
|
/// because C# does not support pointers to type parameters.</para>
|
||||||
|
/// <para>This creates mismatching types -
|
||||||
|
/// for example, char and const char* which is mapped to string.</para>
|
||||||
|
/// </remarks>
|
||||||
|
public class SpecializationMethodsWithDependentPointersPass : TranslationUnitPass |
||||||
|
{ |
||||||
|
public SpecializationMethodsWithDependentPointersPass() |
||||||
|
{ |
||||||
|
VisitOptions.VisitClassBases = false; |
||||||
|
VisitOptions.VisitClassFields = false; |
||||||
|
VisitOptions.VisitClassMethods = false; |
||||||
|
VisitOptions.VisitClassProperties = false; |
||||||
|
VisitOptions.VisitEventParameters = false; |
||||||
|
VisitOptions.VisitFunctionParameters = false; |
||||||
|
VisitOptions.VisitFunctionReturnType = false; |
||||||
|
VisitOptions.VisitNamespaceEnums = false; |
||||||
|
VisitOptions.VisitNamespaceEvents = false; |
||||||
|
VisitOptions.VisitNamespaceTemplates = false; |
||||||
|
VisitOptions.VisitNamespaceTypedefs = false; |
||||||
|
VisitOptions.VisitNamespaceVariables = false; |
||||||
|
VisitOptions.VisitTemplateArguments = false; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitASTContext(ASTContext context) |
||||||
|
{ |
||||||
|
base.VisitASTContext(context); |
||||||
|
foreach (var extension in extensions) |
||||||
|
{ |
||||||
|
var index = extension.Namespace.Declarations.IndexOf(extension.OriginalClass); |
||||||
|
extension.Namespace.Declarations.Insert(index, extension); |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitClassDecl(Class @class) |
||||||
|
{ |
||||||
|
if (!base.VisitClassDecl(@class) || !@class.IsDependent) |
||||||
|
return false; |
||||||
|
|
||||||
|
var methodsWithDependentPointers = @class.Methods.Where( |
||||||
|
m => !m.Ignore && @class.Properties.All(p => p.SetMethod != m) && |
||||||
|
(m.OriginalReturnType.Type.IsDependentPointer() || |
||||||
|
m.Parameters.Any(p => p.Type.IsDependentPointer()))).ToList(); |
||||||
|
if (!methodsWithDependentPointers.Any()) |
||||||
|
return false; |
||||||
|
|
||||||
|
var classExtensions = new Class { Name = $"{@class.Name}Extensions", IsStatic = true }; |
||||||
|
foreach (var specialization in @class.Specializations.Where(s => !s.Ignore)) |
||||||
|
foreach (var method in methodsWithDependentPointers.Where( |
||||||
|
m => m.SynthKind == FunctionSynthKind.None)) |
||||||
|
{ |
||||||
|
var specializedMethod = specialization.Methods.First( |
||||||
|
m => m.InstantiatedFrom == method); |
||||||
|
Method extensionMethod = GetExtensionMethodForDependentPointer(specializedMethod); |
||||||
|
classExtensions.Methods.Add(extensionMethod); |
||||||
|
extensionMethod.Namespace = classExtensions; |
||||||
|
specializedMethod.ExplicitlyIgnore(); |
||||||
|
method.ExplicitlyIgnore(); |
||||||
|
var property = @class.Properties.FirstOrDefault( |
||||||
|
p => p.GetMethod == method || p.SetMethod == method); |
||||||
|
if (property != null) |
||||||
|
{ |
||||||
|
property.ExplicitlyIgnore(); |
||||||
|
extensionMethod.GenerationKind = GenerationKind.Generate; |
||||||
|
} |
||||||
|
} |
||||||
|
classExtensions.Namespace = @class.Namespace; |
||||||
|
classExtensions.OriginalClass = @class; |
||||||
|
extensions.Add(classExtensions); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
private static Method GetExtensionMethodForDependentPointer(Method specializedMethod) |
||||||
|
{ |
||||||
|
var extensionMethod = new Method(specializedMethod); |
||||||
|
|
||||||
|
foreach (var parameter in extensionMethod.Parameters) |
||||||
|
{ |
||||||
|
var qualType = parameter.QualifiedType; |
||||||
|
RemoveTemplateSubstitution(ref qualType); |
||||||
|
parameter.QualifiedType = qualType; |
||||||
|
} |
||||||
|
|
||||||
|
if (!specializedMethod.IsStatic) |
||||||
|
{ |
||||||
|
if (specializedMethod.IsConstructor) |
||||||
|
{ |
||||||
|
extensionMethod.Name = specializedMethod.Namespace.Name; |
||||||
|
if (extensionMethod.OriginalReturnType.Type.IsPrimitiveType(PrimitiveType.Void)) |
||||||
|
extensionMethod.OriginalReturnType = new QualifiedType(new PointerType( |
||||||
|
new QualifiedType(new TagType(specializedMethod.Namespace)))); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
var thisParameter = new Parameter(); |
||||||
|
thisParameter.QualifiedType = new QualifiedType(new PointerType( |
||||||
|
new QualifiedType(new TagType(specializedMethod.Namespace)))); |
||||||
|
thisParameter.Name = "@this"; |
||||||
|
thisParameter.Kind = ParameterKind.Extension; |
||||||
|
extensionMethod.Parameters.Insert(0, thisParameter); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
extensionMethod.OriginalFunction = specializedMethod; |
||||||
|
extensionMethod.Kind = CXXMethodKind.Normal; |
||||||
|
extensionMethod.IsStatic = true; |
||||||
|
|
||||||
|
var qualReturnType = extensionMethod.OriginalReturnType; |
||||||
|
RemoveTemplateSubstitution(ref qualReturnType); |
||||||
|
extensionMethod.OriginalReturnType = qualReturnType; |
||||||
|
|
||||||
|
return extensionMethod; |
||||||
|
} |
||||||
|
|
||||||
|
private static void RemoveTemplateSubstitution(ref QualifiedType qualType) |
||||||
|
{ |
||||||
|
var substitution = qualType.Type as TemplateParameterSubstitutionType; |
||||||
|
if (substitution != null) |
||||||
|
qualType.Type = substitution.Replacement.Type; |
||||||
|
else |
||||||
|
{ |
||||||
|
var type = qualType.Type.Desugar(); |
||||||
|
while (type.IsAddress()) |
||||||
|
{ |
||||||
|
var pointee = ((PointerType) type).Pointee.Desugar(false); |
||||||
|
if (pointee.IsAddress()) |
||||||
|
type = pointee; |
||||||
|
else |
||||||
|
{ |
||||||
|
substitution = pointee as TemplateParameterSubstitutionType; |
||||||
|
if (substitution != null) |
||||||
|
((PointerType) type).QualifiedPointee.Type = substitution.Replacement.Type; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private List<Class> extensions = new List<Class>(); |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue