Browse Source

Bound the supported specialisations with generic syntax in the generated C#. (#880)

Signed-off-by: Dimitar Dobrev <dpldobrev@protonmail.com>
pull/886/head
Dimitar Dobrev 8 years ago committed by GitHub
parent
commit
9c0f80f69d
  1. 16
      src/AST/ClassExtensions.cs
  2. 3
      src/AST/Function.cs
  3. 5
      src/AST/FunctionExtensions.cs
  4. 8
      src/AST/Type.cs
  5. 41
      src/AST/TypeExtensions.cs
  6. 3
      src/Generator/Driver.cs
  7. 3
      src/Generator/Generators/CLI/CLIHeaders.cs
  8. 203
      src/Generator/Generators/CSharp/CSharpSources.cs
  9. 126
      src/Generator/Generators/CSharp/CSharpSourcesExtensions.cs
  10. 7
      src/Generator/Generators/CSharp/CSharpTypePrinter.cs
  11. 3
      src/Generator/Passes/CheckIgnoredDecls.cs
  12. 8
      src/Generator/Passes/ConstructorToConversionOperatorPass.cs
  13. 42
      src/Generator/Passes/IgnoreSystemDeclarationsPass.cs
  14. 163
      src/Generator/Passes/SpecializationMethodsWithDependentPointersPass.cs
  15. 52
      src/Generator/Passes/TrimSpecializationsPass.cs
  16. 39
      src/Generator/Types/Std/Stdlib.cs
  17. 7
      src/Generator/Types/TypeMapDatabase.cs

16
src/AST/ClassExtensions.cs

@ -185,5 +185,21 @@ namespace CppSharp.AST @@ -185,5 +185,21 @@ namespace CppSharp.AST
{
return units.Where(u => u.IsGenerated && (u.HasDeclarations || u.IsSystemHeader) && u.IsValid);
}
public static List<ClassTemplateSpecialization> GetSpecializationsToGenerate(
this Class classTemplate)
{
if (classTemplate.Fields.Any(
f => f.Type.Desugar() is TemplateParameterType))
return classTemplate.Specializations;
var specializations = new List<ClassTemplateSpecialization>();
var specialization = classTemplate.Specializations.FirstOrDefault(s => !s.Ignore);
if (specialization == null)
specializations.Add(classTemplate.Specializations[0]);
else
specializations.Add(specialization);
return specializations;
}
}
}

3
src/AST/Function.cs

@ -27,7 +27,8 @@ namespace CppSharp.AST @@ -27,7 +27,8 @@ namespace CppSharp.AST
Regular,
IndirectReturnType,
OperatorParameter,
ImplicitDestructorParameter
ImplicitDestructorParameter,
Extension
}
public class Parameter : Declaration, ITypedDecl

5
src/AST/FunctionExtensions.cs

@ -11,7 +11,7 @@ namespace CppSharp.AST @@ -11,7 +11,7 @@ namespace CppSharp.AST
{
var @params = new List<Parameter>();
var method = function as Method;
var method = (function.OriginalFunction ?? function) as Method;
var isInstanceMethod = method != null && !method.IsStatic;
var pointer = new QualifiedType(new PointerType(new QualifiedType(new BuiltinType(PrimitiveType.Void))));
@ -36,7 +36,8 @@ namespace CppSharp.AST @@ -36,7 +36,8 @@ namespace CppSharp.AST
}
var i = 0;
foreach (var param in function.Parameters.Where(p => p.Kind != ParameterKind.OperatorParameter))
foreach (var param in function.Parameters.Where(
p => p.Kind != ParameterKind.OperatorParameter && p.Kind != ParameterKind.Extension))
{
@params.Add(new Parameter
{

8
src/AST/Type.cs

@ -821,10 +821,10 @@ namespace CppSharp.AST @@ -821,10 +821,10 @@ namespace CppSharp.AST
var type = obj as TemplateParameterType;
if (type == null) return false;
return Parameter.Equals(type.Parameter)
&& Depth.Equals(type.Depth)
&& Index.Equals(type.Index)
&& IsParameterPack.Equals(type.IsParameterPack);
return Parameter == type.Parameter
&& Depth == type.Depth
&& Index == type.Index
&& IsParameterPack == type.IsParameterPack;
}
public override int GetHashCode()

41
src/AST/TypeExtensions.cs

@ -185,27 +185,39 @@ @@ -185,27 +185,39 @@
return @enum != null;
}
public static Type Desugar(this Type t)
public static Type Desugar(this Type t, bool resolveTemplateSubstitution = true)
{
var typeDef = t as TypedefType;
if (typeDef != null)
{
var decl = typeDef.Declaration.Type;
if (decl != null)
return decl.Desugar();
return decl.Desugar(resolveTemplateSubstitution);
}
var substType = t as TemplateParameterSubstitutionType;
if (substType != null)
if (resolveTemplateSubstitution)
{
var replacement = substType.Replacement.Type;
if (replacement != null)
return replacement.Desugar();
var substType = t as TemplateParameterSubstitutionType;
if (substType != null)
{
var replacement = substType.Replacement.Type;
if (replacement != null)
return replacement.Desugar(resolveTemplateSubstitution);
}
}
var injectedType = t as InjectedClassNameType;
if (injectedType != null)
{
if (injectedType.InjectedSpecializationType.Type != null)
return injectedType.InjectedSpecializationType.Type.Desugar(
resolveTemplateSubstitution);
return new TagType(injectedType.Class);
}
var attributedType = t as AttributedType;
if (attributedType != null)
return attributedType.Equivalent.Type.Desugar();
return attributedType.Equivalent.Type.Desugar(resolveTemplateSubstitution);
return t;
}
@ -322,5 +334,18 @@ @@ -322,5 +334,18 @@
}
return left.Equals(right);
}
public static bool IsDependentPointer(this Type type)
{
var desugared = type.Desugar();
if (desugared.IsAddress())
{
var pointee = desugared.GetFinalPointee().Desugar();
return pointee.IsDependent
&& !(pointee is TemplateSpecializationType)
&& !(pointee is InjectedClassNameType);
}
return false;
}
}
}

3
src/Generator/Driver.cs

@ -335,6 +335,9 @@ namespace CppSharp @@ -335,6 +335,9 @@ namespace CppSharp
TranslationUnitPasses.AddPass(new GetterSetterToPropertyPass());
TranslationUnitPasses.AddPass(new StripUnusedSystemTypesPass());
if (Options.IsCSharpGenerator)
TranslationUnitPasses.AddPass(new SpecializationMethodsWithDependentPointersPass());
if (Options.GeneratorKind == GeneratorKind.CLI ||
Options.GeneratorKind == GeneratorKind.CSharp)
TranslationUnitPasses.RenameDeclsUpperCase(RenameTargets.Any &~ RenameTargets.Parameter);

3
src/Generator/Generators/CLI/CLIHeaders.cs

@ -834,7 +834,8 @@ namespace CppSharp.Generators.CLI @@ -834,7 +834,8 @@ namespace CppSharp.Generators.CLI
var typeName = TypePrinter.VisitPrimitiveType(@enum.BuiltinType.Type,
new TypeQualifiers());
if (@enum.BuiltinType.Type != PrimitiveType.Int)
if (@enum.BuiltinType.Type != PrimitiveType.Int &&
@enum.BuiltinType.Type != PrimitiveType.Null)
Write(" : {0}", typeName);
NewLine();

203
src/Generator/Generators/CSharp/CSharpSources.cs

@ -207,58 +207,41 @@ namespace CppSharp.Generators.CSharp @@ -207,58 +207,41 @@ namespace CppSharp.Generators.CSharp
if (classTemplate.Specializations.Count == 0)
return;
var specializations = GetSpecializationsToGenerate(classTemplate);
var specializations = classTemplate.GetSpecializationsToGenerate();
bool generateClass = specializations.Any(s => s.IsGenerated);
if (!generateClass)
{
PushBlock(BlockKind.Namespace);
WriteLine("namespace {0}{1}",
classTemplate.OriginalNamespace is Class ?
classTemplate.OriginalNamespace.Name + '_' : string.Empty,
classTemplate.Name);
WriteStartBraceIndent();
}
PushBlock(BlockKind.Namespace);
WriteLine("namespace {0}{1}",
classTemplate.OriginalNamespace is Class ?
classTemplate.OriginalNamespace.Name + '_' : string.Empty,
classTemplate.Name);
WriteStartBraceIndent();
foreach (var specialization in specializations)
{
if (specialization.Ignore)
GenerateClassInternals(specialization);
else
specialization.Visit(this);
}
GenerateClassInternals(specialization);
foreach (var nestedClass in classTemplate.Classes.Where(c => !c.IsDependent).Union(
specializations[0].Classes.Where(c => !c.IsDependent)))
{
NewLine();
GenerateClassSpecifier(nestedClass);
NewLine();
WriteStartBraceIndent();
GenerateClassInternals(nestedClass);
GenerateClassInternalsOnly(nestedClass);
foreach (var nestedNestedClass in nestedClass.Classes)
{
GenerateClassInternalsOnly(nestedNestedClass);
WriteCloseBraceIndent();
}
WriteCloseBraceIndent();
}
if (!generateClass)
{
WriteCloseBraceIndent();
PopBlock(NewLineKind.BeforeNextBlock);
}
WriteCloseBraceIndent();
PopBlock(NewLineKind.BeforeNextBlock);
}
private static List<ClassTemplateSpecialization> GetSpecializationsToGenerate(Class classTemplate)
private void GenerateClassInternalsOnly(Class c)
{
if (classTemplate.Fields.Any(
f => f.Type.Desugar() is TemplateParameterType))
return classTemplate.Specializations;
var specializations = new List<ClassTemplateSpecialization>();
var specialization = classTemplate.Specializations.FirstOrDefault(s => !s.Ignore);
if (specialization == null)
specializations.Add(classTemplate.Specializations[0]);
else
specializations.Add(specialization);
return specializations;
NewLine();
GenerateClassSpecifier(c);
NewLine();
WriteStartBraceIndent();
GenerateClassInternals(c);
}
public override void GenerateDeclarationCommon(Declaration decl)
@ -290,23 +273,14 @@ namespace CppSharp.Generators.CSharp @@ -290,23 +273,14 @@ namespace CppSharp.Generators.CSharp
if (!(@class.Namespace is Class))
GenerateClassTemplateSpecializationInternal(@class);
return true;
if (@class.Specializations.All(s => s.Ignore))
return true;
}
System.Type typeMap = null;
string key = string.Empty;
var cppTypePrinter = new CppTypePrinter { PrintScopeKind = TypePrintScopeKind.Qualified };
foreach (var name in new[] { @class.OriginalName, @class.Visit(cppTypePrinter) })
{
if (Context.TypeMaps.TypeMaps.ContainsKey(name))
{
key = name;
typeMap = Context.TypeMaps.TypeMaps[key];
// disable the type map for the mapped class itself so that operator params are not mapped
Context.TypeMaps.TypeMaps.Remove(key);
break;
}
}
var typeMaps = new List<System.Type>();
var keys = new List<string>();
// disable the type maps, if any, for this class because of copy ctors, operators and others
CSharpSourcesExtensions.DisableTypeMap(@class, typeMaps, keys, Context);
PushBlock(BlockKind.Class);
GenerateDeclarationCommon(@class);
@ -315,12 +289,12 @@ namespace CppSharp.Generators.CSharp @@ -315,12 +289,12 @@ namespace CppSharp.Generators.CSharp
NewLine();
WriteStartBraceIndent();
if (!@class.IsAbstractImpl)
if (!@class.IsAbstractImpl && !@class.IsDependent)
GenerateClassInternals(@class);
VisitDeclContext(@class);
if (@class.IsDependent || !@class.IsGenerated)
if (!@class.IsGenerated)
goto exit;
if (ShouldGenerateClassNativeField(@class))
@ -368,8 +342,8 @@ namespace CppSharp.Generators.CSharp @@ -368,8 +342,8 @@ namespace CppSharp.Generators.CSharp
WriteCloseBraceIndent();
PopBlock(NewLineKind.BeforeNextBlock);
if (typeMap != null)
Context.TypeMaps.TypeMaps.Add(key, typeMap);
for (int i = 0; i < typeMaps.Count; i++)
Context.TypeMaps.TypeMaps.Add(keys[i], typeMaps[i]);
return true;
}
@ -464,8 +438,8 @@ namespace CppSharp.Generators.CSharp @@ -464,8 +438,8 @@ namespace CppSharp.Generators.CSharp
var currentSpecialization = @class as ClassTemplateSpecialization;
Class template;
if (currentSpecialization != null &&
GetSpecializationsToGenerate(
template = currentSpecialization.TemplatedDecl.TemplatedClass).Count == 1)
(template = currentSpecialization.TemplatedDecl.TemplatedClass)
.GetSpecializationsToGenerate().Count == 1)
foreach (var specialization in template.Specializations.Where(s => !s.Ignore))
GatherClassInternalFunctions(specialization, includeCtors, functions);
else
@ -589,6 +563,8 @@ namespace CppSharp.Generators.CSharp @@ -589,6 +563,8 @@ namespace CppSharp.Generators.CSharp
keywords.Add(SafeIdentifier(@class.Name));
Write(string.Join(" ", keywords));
if (@class.IsDependent && @class.TemplateParameters.Any())
Write($"<{string.Join(", ", @class.TemplateParameters.Select(p => p.Name))}>");
var bases = new List<string>();
@ -670,13 +646,18 @@ namespace CppSharp.Generators.CSharp @@ -670,13 +646,18 @@ namespace CppSharp.Generators.CSharp
NewLine();
WriteStartBraceIndent();
GenerateFunctionSetter(property);
this.GenerateMember(@class, c => GenerateFunctionSetter(c, property), true);
}
else if (decl is Variable)
{
NewLine();
WriteStartBraceIndent();
GenerateVariableSetter(decl, @class);
var var = decl as Variable;
this.GenerateMember(@class, c => GenerateVariableSetter(
c is ClassTemplateSpecialization ?
c.Variables.First(v => v.Name == decl.Name) : var),
true);
}
else if (decl is Field)
{
@ -686,13 +667,14 @@ namespace CppSharp.Generators.CSharp @@ -686,13 +667,14 @@ namespace CppSharp.Generators.CSharp
NewLine();
WriteStartBraceIndent();
GenerateFieldSetter(field, @class);
this.GenerateField(@class, field, GenerateFieldSetter, true);
}
WriteCloseBraceIndent();
PopBlock(NewLineKind.BeforeNextBlock);
}
private void GenerateVariableSetter<T>(T decl, Class @class) where T : Declaration, ITypedDecl
private void GenerateVariableSetter<T>(T decl) where T : Declaration, ITypedDecl
{
var var = decl as Variable;
@ -703,6 +685,7 @@ namespace CppSharp.Generators.CSharp @@ -703,6 +685,7 @@ namespace CppSharp.Generators.CSharp
string ptr = Generator.GeneratedIdentifier("ptr");
var arrayType = decl.Type as ArrayType;
var @class = decl.Namespace as Class;
var isRefTypeArray = arrayType != null && @class != null && @class.IsRefType;
if (isRefTypeArray)
WriteLine($@"var {ptr} = {
@ -743,8 +726,9 @@ namespace CppSharp.Generators.CSharp @@ -743,8 +726,9 @@ namespace CppSharp.Generators.CSharp
WriteCloseBraceIndent();
}
private void GenerateFunctionSetter(Property property)
private void GenerateFunctionSetter(Class @class, Property property)
{
property = GetActualProperty(property, @class);
var param = new Parameter
{
Name = "value",
@ -754,7 +738,6 @@ namespace CppSharp.Generators.CSharp @@ -754,7 +738,6 @@ namespace CppSharp.Generators.CSharp
if (!property.Type.Equals(param.Type) && property.Type.IsEnumType())
param.Name = "&" + param.Name;
var @class = (Class) property.Namespace;
var function = property.SetMethod;
var method = function as Method;
if (function.SynthKind == FunctionSynthKind.AbstractImplCall)
@ -939,7 +922,8 @@ namespace CppSharp.Generators.CSharp @@ -939,7 +922,8 @@ namespace CppSharp.Generators.CSharp
NewLine();
WriteStartBraceIndent();
GenerateFunctionGetter(property);
this.GenerateMember(@class, c => GenerateFunctionGetter(c, property));
}
else if (decl is Field)
{
@ -949,19 +933,22 @@ namespace CppSharp.Generators.CSharp @@ -949,19 +933,22 @@ namespace CppSharp.Generators.CSharp
NewLine();
WriteStartBraceIndent();
GenerateFieldGetter(field, @class);
this.GenerateField(@class, field, GenerateFieldGetter, false);
}
else if (decl is Variable)
{
NewLine();
WriteStartBraceIndent();
GenerateVariableGetter(decl, @class);
var var = decl as Variable;
this.GenerateMember(@class, c => GenerateVariableGetter(
c is ClassTemplateSpecialization ?
c.Variables.First(v => v.Name == decl.Name) : var));
}
WriteCloseBraceIndent();
PopBlock(NewLineKind.BeforeNextBlock);
}
private void GenerateVariableGetter<T>(T decl, Class @class) where T : Declaration, ITypedDecl
private void GenerateVariableGetter<T>(T decl) where T : Declaration, ITypedDecl
{
var var = decl as Variable;
@ -971,6 +958,7 @@ namespace CppSharp.Generators.CSharp @@ -971,6 +958,7 @@ namespace CppSharp.Generators.CSharp
GetLibraryOf(decl), var.Mangled);
var arrayType = decl.Type as ArrayType;
var @class = decl.Namespace as Class;
var isRefTypeArray = arrayType != null && @class != null && @class.IsRefType;
if (isRefTypeArray)
WriteLine("var {0} = {1}{2};", Generator.GeneratedIdentifier("ptr"),
@ -1008,9 +996,9 @@ namespace CppSharp.Generators.CSharp @@ -1008,9 +996,9 @@ namespace CppSharp.Generators.CSharp
WriteCloseBraceIndent();
}
private void GenerateFunctionGetter(Property property)
private void GenerateFunctionGetter(Class @class, Property property)
{
var @class = (Class) property.Namespace;
property = GetActualProperty(property, @class);
if (property.GetMethod.SynthKind == FunctionSynthKind.AbstractImplCall)
GenerateVirtualPropertyCall(property.GetMethod, @class.BaseClass, property);
else if (property.GetMethod.IsVirtual)
@ -1019,6 +1007,17 @@ namespace CppSharp.Generators.CSharp @@ -1019,6 +1007,17 @@ namespace CppSharp.Generators.CSharp
property.GetMethod.Parameters, property.QualifiedType.Type);
}
private static Property GetActualProperty(Property property, Class c)
{
if (!(c is ClassTemplateSpecialization))
return property;
if (property.GetMethod != null
&& property.GetMethod.OperatorKind == CXXOperatorKind.Subscript)
return c.Properties.Single(p => p.GetMethod != null
&& p.GetMethod.InstantiatedFrom == property.GetMethod);
return c.Properties.Single(p => p.Name == property.Name);
}
private void GenerateFieldGetter(Field field, Class @class)
{
var name = @class.Layout.Fields.First(f => f.FieldPtr == field.OriginalPtr).Name;
@ -1884,18 +1883,22 @@ namespace CppSharp.Generators.CSharp @@ -1884,18 +1883,22 @@ namespace CppSharp.Generators.CSharp
Context.Symbols.FindLibraryBySymbol(dtor.Mangled, out library))
{
WriteLine("if (disposing)");
if (dtor.IsVirtual)
{
if (@class.IsDependent || dtor.IsVirtual)
WriteStartBraceIndent();
GenerateDestructorCall(dtor);
WriteCloseBraceIndent();
}
else
{
PushIndent();
GenerateInternalFunctionCall(dtor);
if (dtor.IsVirtual)
this.GenerateMember(@class, c => GenerateDestructorCall(
c is ClassTemplateSpecialization ?
c.Methods.First(m => m.InstantiatedFrom == dtor) : dtor), true);
else
this.GenerateMember(@class, c => GenerateInternalFunctionCall(
c is ClassTemplateSpecialization ?
c.Methods.First(m => m.InstantiatedFrom == dtor) : dtor), true);
if (@class.IsDependent || dtor.IsVirtual)
WriteCloseBraceIndent();
else
PopIndent();
}
}
}
@ -1931,23 +1934,22 @@ namespace CppSharp.Generators.CSharp @@ -1931,23 +1934,22 @@ namespace CppSharp.Generators.CSharp
PopBlock(NewLineKind.BeforeNextBlock);
}
var suffix = @class.IsAbstract ? "Internal" : string.Empty;
var printedClass = @class.Visit(TypePrinter);
var ctorCall = $"{printedClass}{printedClass.NameSuffix}{suffix}";
if (!@class.IsAbstractImpl)
{
PushBlock(BlockKind.Method);
var printedClass = @class.Visit(TypePrinter);
WriteLine("internal static {0}{1}{2} {3}(global::System.IntPtr native, bool skipVTables = false)",
@class.NeedsBase && !@class.BaseClass.IsInterface ? "new " : string.Empty,
printedClass, printedClass.NameSuffix, Helpers.CreateInstanceIdentifier);
WriteStartBraceIndent();
var suffix = @class.IsAbstract ? "Internal" : string.Empty;
var ctorCall = $"{printedClass}{printedClass.NameSuffix}{suffix}";
WriteLine("return new {0}(native.ToPointer(), skipVTables);", ctorCall);
WriteCloseBraceIndent();
PopBlock(NewLineKind.BeforeNextBlock);
}
GenerateNativeConstructorByValue(@class, ctorCall);
this.GenerateNativeConstructorsByValue(@class);
PushBlock(BlockKind.Method);
WriteLine("{0} {1}(void* native, bool skipVTables = false){2}",
@ -2004,7 +2006,7 @@ namespace CppSharp.Generators.CSharp @@ -2004,7 +2006,7 @@ namespace CppSharp.Generators.CSharp
PopBlock(NewLineKind.BeforeNextBlock);
}
private void GenerateNativeConstructorByValue(Class @class, string ctorCall)
public void GenerateNativeConstructorByValue(Class @class, string returnType)
{
TypePrinter.PushContext(TypePrinterContextKind.Native);
var @internal = (@class.IsAbstractImpl ? @class.BaseClass : @class).Visit(TypePrinter);
@ -2014,9 +2016,10 @@ namespace CppSharp.Generators.CSharp @@ -2014,9 +2016,10 @@ namespace CppSharp.Generators.CSharp
{
PushBlock(BlockKind.Method);
WriteLine("internal static {0} {1}({2} native, bool skipVTables = false)",
@class.Visit(TypePrinter), Helpers.CreateInstanceIdentifier, @internal);
returnType, Helpers.CreateInstanceIdentifier, @internal);
WriteStartBraceIndent();
WriteLine("return new {0}(native, skipVTables);", ctorCall);
var suffix = @class.IsAbstract ? "Internal" : "";
WriteLine($"return new {returnType}{suffix}(native, skipVTables);");
WriteCloseBraceIndent();
PopBlock(NewLineKind.BeforeNextBlock);
}
@ -2201,7 +2204,19 @@ namespace CppSharp.Generators.CSharp @@ -2201,7 +2204,19 @@ namespace CppSharp.Generators.CSharp
goto SkipImpl;
}
GenerateMethodBody(method);
if (method.SynthKind == FunctionSynthKind.DefaultValueOverload ||
method.SynthKind == FunctionSynthKind.ComplementOperator)
{
GenerateMethodBody(method);
}
else
{
var isVoid = method.OriginalReturnType.Type.Desugar().IsPrimitiveType(PrimitiveType.Void) ||
method.IsConstructor;
this.GenerateMember(@class, c => GenerateMethodBody(
c is ClassTemplateSpecialization ?
c.Methods.First(m => m.InstantiatedFrom == method) : method), isVoid);
}
SkipImpl:
@ -2671,6 +2686,13 @@ namespace CppSharp.Generators.CSharp @@ -2671,6 +2686,13 @@ namespace CppSharp.Generators.CSharp
if (needsReturn && !originalFunction.HasIndirectReturnTypeParameter)
Write("var {0} = ", Helpers.ReturnIdentifier);
if (method != null && !method.IsConstructor && method.OriginalFunction != null &&
((Method) method.OriginalFunction).IsConstructor)
{
WriteLine($@"Marshal.AllocHGlobal({
((Class) method.OriginalNamespace).Layout.Size});");
names.Insert(0, Helpers.ReturnIdentifier);
}
WriteLine("{0}({1});", functionName, string.Join(", ", names));
var cleanups = new List<TextGenerator>();
@ -2955,7 +2977,8 @@ namespace CppSharp.Generators.CSharp @@ -2955,7 +2977,8 @@ namespace CppSharp.Generators.CSharp
var typeName = TypePrinter.VisitPrimitiveType(@enum.BuiltinType.Type,
new TypeQualifiers());
if (@enum.BuiltinType.Type != PrimitiveType.Int)
if (@enum.BuiltinType.Type != PrimitiveType.Int &&
@enum.BuiltinType.Type != PrimitiveType.Null)
Write(" : {0}", typeName);
NewLine();

126
src/Generator/Generators/CSharp/CSharpSourcesExtensions.cs

@ -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()))));
}
}
}

7
src/Generator/Generators/CSharp/CSharpTypePrinter.cs

@ -563,8 +563,6 @@ namespace CppSharp.Generators.CSharp @@ -563,8 +563,6 @@ namespace CppSharp.Generators.CSharp
if (ContextKind == TypePrinterContextKind.Native)
return $@"{VisitClassDecl(specialization)}{
Helpers.GetSuffixForInternal(specialization)}";
if (specialization.IsExplicitlyGenerated)
return $"{VisitClassDecl(specialization)}";
var args = string.Join(", ", specialization.Arguments.Select(VisitTemplateArgument));
return $"{VisitClassDecl(specialization)}<{args}>";
}
@ -660,13 +658,14 @@ namespace CppSharp.Generators.CSharp @@ -660,13 +658,14 @@ namespace CppSharp.Generators.CSharp
if (ContextKind == TypePrinterContextKind.Native)
return $"{type} {param.Name}";
var extension = param.Kind == ParameterKind.Extension ? "this " : string.Empty;
var usage = GetParameterUsage(param.Usage);
if (param.DefaultArgument == null || !Options.GenerateDefaultValuesForArguments)
return $"{usage}{type} {param.Name}";
return $"{extension}{usage}{type} {param.Name}";
var defaultValue = expressionPrinter.VisitParameter(param);
return $"{usage}{type} {param.Name} = {defaultValue}";
return $"{extension}{usage}{type} {param.Name} = {defaultValue}";
}
public override TypePrinterResult VisitDelegate(FunctionType function)

3
src/Generator/Passes/CheckIgnoredDecls.cs

@ -112,7 +112,8 @@ namespace CppSharp.Passes @@ -112,7 +112,8 @@ namespace CppSharp.Passes
public override bool VisitFunctionDecl(Function function)
{
if (!VisitDeclaration(function) || function.IsSynthetized)
if (!VisitDeclaration(function) || function.IsSynthetized
|| function.IsExplicitlyGenerated)
return false;
var ret = function.OriginalReturnType;

8
src/Generator/Passes/ConstructorToConversionOperatorPass.cs

@ -34,7 +34,15 @@ namespace CppSharp.Passes @@ -34,7 +34,15 @@ namespace CppSharp.Passes
return false;
}
if (method.Parameters[0].Type.IsDependentPointer())
return false;
var parameter = method.Parameters[0];
Class @class;
var paramType = (parameter.Type.GetFinalPointee() ?? parameter.Type).Desugar();
if (paramType.TryGetClass(out @class) && @class == method.Namespace)
return false;
// TODO: disable implicit operators for C++/CLI because they seem not to be support parameters
if (!Options.IsCSharpGenerator)
{

42
src/Generator/Passes/IgnoreSystemDeclarationsPass.cs

@ -54,12 +54,33 @@ namespace CppSharp.Passes @@ -54,12 +54,33 @@ namespace CppSharp.Passes
foreach (var method in @class.Methods.Where(m => !m.IsDestructor && m.OriginalName != "c_str"))
method.ExplicitlyIgnore();
foreach (var specialization in @class.Specializations.Where(s => !s.Ignore))
{
foreach (var method in specialization.Methods)
{
if (method.IsDestructor || method.OriginalName == "c_str" ||
(method.IsConstructor && method.Parameters.Count == 2 &&
method.Parameters[0].Type.Desugar().IsPointerToPrimitiveType(PrimitiveType.Char) &&
!method.Parameters[1].Type.Desugar().IsPrimitiveType()))
{
method.GenerationKind = GenerationKind.Generate;
method.InstantiatedFrom.GenerationKind = GenerationKind.Generate;
method.InstantiatedFrom.Namespace.GenerationKind = GenerationKind.Generate;
}
else
{
method.ExplicitlyIgnore();
}
}
}
break;
case "allocator":
foreach (var method in @class.Methods.Where(m => !m.IsConstructor || m.Parameters.Any()))
method.ExplicitlyIgnore();
foreach (var specialization in @class.Specializations.Where(s => !s.Ignore))
{
foreach (var method in specialization.Methods.Where(m => !m.IsDestructor && m.OriginalName != "c_str"))
method.ExplicitlyIgnore();
var ctor = specialization.Methods.Single(m => m.IsConstructor && m.Parameters.Count == 2 &&
m.Parameters[0].Type.Desugar().IsPointerToPrimitiveType(PrimitiveType.Char) &&
!m.Parameters[1].Type.Desugar().IsPrimitiveType());
var ctor = specialization.Methods.Single(m => m.IsConstructor && !m.Parameters.Any());
ctor.GenerationKind = GenerationKind.Generate;
ctor.InstantiatedFrom.GenerationKind = GenerationKind.Generate;
ctor.InstantiatedFrom.Namespace.GenerationKind = GenerationKind.Generate;
@ -67,20 +88,19 @@ namespace CppSharp.Passes @@ -67,20 +88,19 @@ namespace CppSharp.Passes
parameter.DefaultArgument = null;
}
break;
case "allocator":
foreach (var method in @class.Methods.Where(m => !m.IsConstructor || m.Parameters.Any()))
method.ExplicitlyIgnore();
foreach (var specialization in @class.Specializations)
foreach (var method in specialization.Methods.Where(
m => !m.IsConstructor || m.Parameters.Any()))
method.ExplicitlyIgnore();
break;
case "char_traits":
foreach (var method in @class.Methods)
method.ExplicitlyIgnore();
foreach (var specialization in @class.Specializations)
{
foreach (var method in specialization.Methods)
method.ExplicitlyIgnore();
if (specialization.Arguments[0].Type.Type.IsPrimitiveType(PrimitiveType.Char))
{
specialization.GenerationKind = GenerationKind.Generate;
specialization.TemplatedDecl.TemplatedDecl.GenerationKind = GenerationKind.Generate;
}
}
break;
}
return true;

163
src/Generator/Passes/SpecializationMethodsWithDependentPointersPass.cs

@ -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 &lt;typename T&gt;</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>();
}
}

52
src/Generator/Passes/TrimSpecializationsPass.cs

@ -8,6 +8,20 @@ namespace CppSharp.Passes @@ -8,6 +8,20 @@ namespace CppSharp.Passes
{
public class TrimSpecializationsPass : TranslationUnitPass
{
public TrimSpecializationsPass()
{
VisitOptions.VisitClassBases = 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)
{
var result = base.VisitASTContext(context);
@ -22,13 +36,30 @@ namespace CppSharp.Passes @@ -22,13 +36,30 @@ namespace CppSharp.Passes
return false;
if (@class.IsDependent)
{
templates.Add(@class);
foreach (var specialization in @class.Specializations.Where(
s => s.IsExplicitlyGenerated))
{
specialization.Visit(this);
foreach (var type in from a in specialization.Arguments
where a.Type.Type != null
select a.Type.Type.Desugar())
CheckForInternalSpecialization(specialization, type);
}
}
else
foreach (var @base in @class.Bases.Where(b => b.IsClass))
{
var specialization = @base.Class as ClassTemplateSpecialization;
if (specialization != null)
{
specializations.Add(specialization);
foreach (var field in specialization.Fields)
field.Visit(this);
foreach (var method in specialization.Methods)
method.Visit(this);
}
}
return true;
@ -63,12 +94,7 @@ namespace CppSharp.Passes @@ -63,12 +94,7 @@ namespace CppSharp.Passes
if (!base.VisitDeclaration(field))
return false;
ASTUtils.CheckTypeForSpecialization(field.Type, field,
s =>
{
if (!specializations.Contains(s))
internalSpecializations.Add(s);
}, Context.TypeMaps, true);
CheckForInternalSpecialization(field, field.Type);
return true;
}
@ -124,6 +150,20 @@ namespace CppSharp.Passes @@ -124,6 +150,20 @@ namespace CppSharp.Passes
template.ExplicitlyIgnore();
}
private void CheckForInternalSpecialization(Declaration container, AST.Type type)
{
ASTUtils.CheckTypeForSpecialization(type, container,
s =>
{
if (!specializations.Contains(s))
{
internalSpecializations.Add(s);
foreach (var f in s.Fields)
f.Visit(this);
}
}, Context.TypeMaps, true);
}
private HashSet<ClassTemplateSpecialization> specializations = new HashSet<ClassTemplateSpecialization>();
private HashSet<ClassTemplateSpecialization> internalSpecializations = new HashSet<ClassTemplateSpecialization>();
private HashSet<Class> templates = new HashSet<Class>();

39
src/Generator/Types/Std/Stdlib.cs

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using CppSharp.AST;
using CppSharp.AST.Extensions;
@ -27,7 +28,7 @@ namespace CppSharp.Types.Std @@ -27,7 +28,7 @@ namespace CppSharp.Types.Std
}
}
[TypeMap("std::basic_string<char, std::char_traits<char>, std::allocator<char>>")]
[TypeMap("basic_string<char, char_traits<char>, allocator<char>>")]
public class String : TypeMap
{
public override string CLISignature(TypePrinterContext ctx)
@ -69,9 +70,10 @@ namespace CppSharp.Types.Std @@ -69,9 +70,10 @@ namespace CppSharp.Types.Std
var allocator = ctx.Context.ASTContext.FindClass("allocator", false, true).First(
a => a.IsDependent && a.TranslationUnit.IsSystemHeader);
var allocatorChar = allocator.Specializations.First(s => !s.Ignore);
string qualifiedBasicString = GetQualifiedBasicString(basicString);
if (type.IsPointer() || (type.IsReference() && ctx.Declaration is Field))
{
ctx.Return.Write($@"new {basicString.Visit(typePrinter)}({
ctx.Return.Write($@"{qualifiedBasicString}Extensions.{basicString.Name}({
ctx.Parameter.Name}, new {allocatorChar.Visit(typePrinter)}()).{
Helpers.InstanceIdentifier}");
}
@ -81,8 +83,9 @@ namespace CppSharp.Types.Std @@ -81,8 +83,9 @@ namespace CppSharp.Types.Std
var varBasicString = $"__basicString{ctx.ParameterIndex}";
ctx.Before.WriteLine($@"var {varAllocator} = new {
allocatorChar.Visit(typePrinter)}();");
ctx.Before.WriteLine($@"var {varBasicString} = new {
basicString.Visit(typePrinter)}({ctx.Parameter.Name}, {varAllocator});");
ctx.Before.WriteLine($@"var {varBasicString} = {
qualifiedBasicString}Extensions.{basicString.Name}({ctx.Parameter.Name}, {
varAllocator});");
ctx.Return.Write($"{varBasicString}.{Helpers.InstanceIdentifier}");
ctx.Cleanup.WriteLine($@"{varBasicString}.Dispose({
(type.IsPointer() ? "true" : "false")});");
@ -94,25 +97,41 @@ namespace CppSharp.Types.Std @@ -94,25 +97,41 @@ namespace CppSharp.Types.Std
{
var type = ctx.ReturnType.Type.Desugar();
ClassTemplateSpecialization basicString = GetBasicString(type);
var c_str = basicString.Properties.First(p => p.OriginalName == "c_str");
var c_str = basicString.Methods.First(m => m.OriginalName == "c_str");
var typePrinter = new CSharpTypePrinter(ctx.Context);
string qualifiedBasicString = GetQualifiedBasicString(basicString);
const string varBasicString = "__basicStringRet";
ctx.Before.WriteLine("var {0} = {1}.{2}({3});",
varBasicString, basicString.Visit(typePrinter),
Helpers.CreateInstanceIdentifier, ctx.ReturnVarName);
ctx.Before.WriteLine($@"var {varBasicString} = {
basicString.Visit(typePrinter)}.{Helpers.CreateInstanceIdentifier}({
ctx.ReturnVarName});");
if (type.IsAddress())
{
ctx.Return.Write($"{varBasicString}.{c_str.Name}");
ctx.Return.Write($@"{qualifiedBasicString}Extensions.{c_str.Name}({
varBasicString})");
}
else
{
const string varString = "__stringRet";
ctx.Before.WriteLine($"var {varString} = {varBasicString}.{c_str.Name};");
ctx.Before.WriteLine($@"var {varString} = {
qualifiedBasicString}Extensions.{c_str.Name}({varBasicString});");
ctx.Before.WriteLine($"{varBasicString}.Dispose(false);");
ctx.Return.Write(varString);
}
}
private static string GetQualifiedBasicString(ClassTemplateSpecialization basicString)
{
var declContext = basicString.TemplatedDecl.TemplatedDecl;
var names = new Stack<string>();
while (!(declContext is TranslationUnit))
{
names.Push(declContext.Name);
declContext = declContext.Namespace;
}
var qualifiedBasicString = string.Join(".", names);
return $"global::{qualifiedBasicString}";
}
private static ClassTemplateSpecialization GetBasicString(Type type)
{
var desugared = type.Desugar();

7
src/Generator/Types/TypeMapDatabase.cs

@ -121,12 +121,7 @@ namespace CppSharp.Types @@ -121,12 +121,7 @@ namespace CppSharp.Types
out typeMap);
}
if (FindTypeMap(type.Visit(typePrinter), out typeMap))
{
typeMap.Type = type;
return true;
}
typePrinter.PrintScopeKind = TypePrintScopeKind.Local;
if (FindTypeMap(type.Visit(typePrinter), out typeMap))
{
typeMap.Type = type;

Loading…
Cancel
Save