mirror of https://github.com/mono/CppSharp.git
17 changed files with 585 additions and 144 deletions
@ -0,0 +1,126 @@
@@ -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 @@
@@ -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