mirror of https://github.com/mono/CppSharp.git
c-sharpdotnetmonobindingsbridgecclangcpluspluscppsharpglueinteropparserparsingpinvokeswigsyntax-treevisitorsxamarinxamarin-bindings
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
314 lines
11 KiB
314 lines
11 KiB
using System; |
|
using System.Linq; |
|
using System.Text.RegularExpressions; |
|
using CppSharp.AST; |
|
using CppSharp.AST.Extensions; |
|
using CppSharp.Generators; |
|
using CppSharp.Generators.CSharp; |
|
using CppSharp.Passes; |
|
using CppSharp.Types; |
|
using CppSharp.Utils; |
|
using Attribute = CppSharp.AST.Attribute; |
|
using Type = CppSharp.AST.Type; |
|
|
|
namespace CppSharp.Tests |
|
{ |
|
public class CSharpTestsGenerator : GeneratorTest |
|
{ |
|
public CSharpTestsGenerator(GeneratorKind kind) |
|
: base("CSharp", kind) |
|
{ |
|
} |
|
|
|
public override void Setup(Driver driver) |
|
{ |
|
base.Setup(driver); |
|
|
|
driver.ParserOptions.UnityBuild = true; |
|
driver.ParserOptions.AddSupportedFunctionTemplates("FunctionTemplate"); |
|
} |
|
|
|
public override void SetupPasses(Driver driver) |
|
{ |
|
driver.Context.TranslationUnitPasses.AddPass(new TestAttributesPass()); |
|
var moveFunctionToClassPass = driver.Context.TranslationUnitPasses.FindPass<MoveFunctionToClassPass>(); |
|
driver.Context.TranslationUnitPasses.RemovePass(moveFunctionToClassPass); |
|
driver.Context.TranslationUnitPasses.AddPass(new FunctionToInstanceMethodPass()); |
|
driver.Context.TranslationUnitPasses.AddPass(new MoveFunctionToClassPass()); |
|
driver.Options.MarshalCharAsManagedChar = true; |
|
driver.Options.GenerateDefaultValuesForArguments = true; |
|
driver.Options.GenerateClassTemplates = true; |
|
|
|
var disableNativeToManaged = new ClassGenerationOptions { GenerateNativeToManaged = false }; |
|
driver.Options.GetClassGenerationOptions = e => |
|
{ |
|
return e.Name == "ClassWithoutNativeToManaged" ? disableNativeToManaged : null; |
|
}; |
|
} |
|
|
|
public override void Preprocess(Driver driver, ASTContext ctx) |
|
{ |
|
ctx.SetClassAsValueType("TestCopyConstructorVal"); |
|
ctx.SetClassAsValueType("QGenericArgument"); |
|
ctx.SetClassAsValueType("StructWithPrivateFields"); |
|
ctx.SetClassAsValueType("QPoint"); |
|
ctx.SetClassAsValueType("QSize"); |
|
ctx.SetClassAsValueType("QRect"); |
|
ctx.SetClassAsValueType("CSharp"); |
|
ctx.SetClassAsValueType("StructTestArrayTypeFromTypedef"); |
|
ctx.IgnoreClassWithName("IgnoredTypeInheritingNonIgnoredWithNoEmptyCtor"); |
|
ctx.IgnoreClassWithName("Ignored"); |
|
|
|
var macroRegex = new Regex("(MY_MACRO_TEST_.*)"); |
|
var list = (from unit in ctx.TranslationUnits |
|
where !unit.IsValid || unit.FileName == "CSharp.h" |
|
from macro in unit.PreprocessedEntities.OfType<MacroDefinition>() |
|
where macroRegex.IsMatch(macro.Name) |
|
select macro.Name).ToList(); |
|
var enumTest = ctx.GenerateEnumFromMacros("MyMacroTestEnum", list.ToArray()); |
|
|
|
ctx.GenerateEnumFromMacros("MyMacroTest2Enum", "MY_MACRO_TEST2_.*"); |
|
ctx.GenerateEnumFromMacros("SignedMacroValuesToEnumTest", "SIGNED_MACRO_VALUES_TO_ENUM_TEST_.*"); |
|
ctx.GenerateEnumFromMacros("TestBoolValuedEnums", "TEST_BOOL_VALUED_ENUMS_.*"); |
|
|
|
enumTest.Namespace = new Namespace() |
|
{ |
|
Name = "MacroTest", |
|
Namespace = ctx.TranslationUnits.First(u => u.IsValid && !u.IsSystemHeader) |
|
}; |
|
|
|
// Generate a finalizer for just the one test case. |
|
driver.Options.GenerateFinalizers = true; |
|
driver.Options.GenerateFinalizersFilter = (@class) => @class.Name == "TestFinalizer"; |
|
|
|
// Preserve the original semantics except for our one test class. |
|
driver.Options.ZeroAllocatedMemory = (@class) => @class.Name == "ClassZeroAllocatedMemoryTest"; |
|
} |
|
|
|
public override void Postprocess(Driver driver, ASTContext ctx) |
|
{ |
|
} |
|
|
|
public static void Main(string[] args) |
|
{ |
|
ConsoleDriver.Run(new CSharpTestsGenerator(GeneratorKind.CSharp)); |
|
} |
|
} |
|
|
|
public class TestAttributesPass : TranslationUnitPass |
|
{ |
|
public override bool VisitFunctionDecl(Function function) |
|
{ |
|
if (AlreadyVisited(function) || function.Name != "obsolete") |
|
return false; |
|
|
|
var attribute = new Attribute |
|
{ |
|
Type = typeof(ObsoleteAttribute), |
|
Value = string.Format("\"{0} is obsolete.\"", function.Name) |
|
}; |
|
|
|
function.Attributes.Add(attribute); |
|
|
|
return base.VisitFunctionDecl(function); |
|
} |
|
} |
|
|
|
#region Type Maps |
|
[TypeMap("boolean_t")] |
|
public class BooleanTypeMap : TypeMap |
|
{ |
|
public override Type CSharpSignatureType(TypePrinterContext ctx) |
|
{ |
|
return new BuiltinType(PrimitiveType.Bool); |
|
} |
|
|
|
public override void CSharpMarshalToNative(CSharpMarshalContext ctx) |
|
{ |
|
ctx.Return.Write(ctx.Parameter.Name); |
|
} |
|
|
|
public override void CSharpMarshalToManaged(CSharpMarshalContext ctx) |
|
{ |
|
ctx.Return.Write(ctx.ReturnVarName); |
|
} |
|
} |
|
|
|
[TypeMap("QFlags")] |
|
public class QFlags : TypeMap |
|
{ |
|
public override string CSharpConstruct() |
|
{ |
|
return string.Empty; |
|
} |
|
|
|
public override Type CSharpSignatureType(TypePrinterContext ctx) |
|
{ |
|
return GetEnumType(ctx.Type); |
|
} |
|
|
|
public override void CSharpMarshalToNative(CSharpMarshalContext ctx) |
|
{ |
|
if (ctx.Parameter.Type.Desugar().IsAddress()) |
|
ctx.Return.Write("new global::System.IntPtr(&{0})", ctx.Parameter.Name); |
|
else |
|
ctx.Return.Write(ctx.Parameter.Name); |
|
} |
|
|
|
public override void CSharpMarshalToManaged(CSharpMarshalContext ctx) |
|
{ |
|
if (ctx.ReturnType.Type.Desugar().IsAddress()) |
|
{ |
|
var finalType = ctx.ReturnType.Type.GetFinalPointee() ?? ctx.ReturnType.Type; |
|
var enumType = GetEnumType(finalType); |
|
ctx.Return.Write("*({0}*) {1}", enumType, ctx.ReturnVarName); |
|
} |
|
else |
|
{ |
|
ctx.Return.Write(ctx.ReturnVarName); |
|
} |
|
} |
|
|
|
public override bool IsIgnored => Type.IsDependent; |
|
|
|
private static Type GetEnumType(Type mappedType) |
|
{ |
|
var type = mappedType.Desugar(); |
|
ClassTemplateSpecialization classTemplateSpecialization; |
|
var templateSpecializationType = type as TemplateSpecializationType; |
|
if (templateSpecializationType != null) |
|
return templateSpecializationType.Arguments[0].Type.Type; |
|
var declaration = ((TagType)type).Declaration; |
|
if (declaration.IsDependent) |
|
return new TagType(((Class)declaration).TemplateParameters[0]); |
|
classTemplateSpecialization = (ClassTemplateSpecialization)declaration; |
|
return classTemplateSpecialization.Arguments[0].Type.Type; |
|
} |
|
} |
|
|
|
[TypeMap("DefaultZeroMappedToEnum")] |
|
public class DefaultZeroMappedToEnum : TypeMap |
|
{ |
|
public override string CSharpConstruct() |
|
{ |
|
return string.Empty; |
|
} |
|
|
|
public override Type CSharpSignatureType(TypePrinterContext ctx) |
|
{ |
|
return new TagType(flags ?? (flags = Context.ASTContext.FindEnum("Flags").First())); |
|
} |
|
|
|
public override void CSharpMarshalToNative(CSharpMarshalContext ctx) |
|
{ |
|
ctx.Return.Write(ctx.Parameter.Name); |
|
} |
|
|
|
public override void CSharpMarshalToManaged(CSharpMarshalContext ctx) |
|
{ |
|
ctx.Return.Write(ctx.ReturnVarName); |
|
} |
|
|
|
private Enumeration flags; |
|
} |
|
|
|
[TypeMap("QList")] |
|
public class QList : TypeMap |
|
{ |
|
public override bool IsIgnored |
|
{ |
|
get |
|
{ |
|
var type = (TemplateSpecializationType)Type; |
|
var pointeeType = type.Arguments[0].Type; |
|
var checker = new TypeIgnoreChecker(TypeMapDatabase); |
|
pointeeType.Visit(checker); |
|
return checker.IsIgnored; |
|
} |
|
} |
|
|
|
public override Type CSharpSignatureType(TypePrinterContext ctx) |
|
{ |
|
if (ctx.Kind == TypePrinterContextKind.Native) |
|
{ |
|
var type = (TemplateSpecializationType)ctx.Type.Desugar(); |
|
var specialization = type.GetClassTemplateSpecialization(); |
|
var typePrinter = new CSharpTypePrinter(null); |
|
typePrinter.PushContext(TypePrinterContextKind.Native); |
|
return new CustomType(string.Format($@"{ |
|
specialization.Visit(typePrinter)}{ |
|
(Type.IsAddress() ? "*" : string.Empty)}", specialization.Visit(typePrinter), |
|
Type.IsAddress() ? "*" : string.Empty)); |
|
} |
|
|
|
return new CustomType( |
|
$@"global::System.Collections.Generic.{ |
|
(ctx.MarshalKind == MarshalKind.DefaultExpression ? "List" : "IList")}<{ |
|
ctx.GetTemplateParameterList()}>"); |
|
} |
|
|
|
public override void CSharpMarshalToNative(CSharpMarshalContext ctx) |
|
{ |
|
// pointless, put just so that the generated code compiles |
|
var type = (TemplateSpecializationType)ctx.Parameter.Type.Desugar(); |
|
var specialization = type.GetClassTemplateSpecialization(); |
|
var typePrinter = new CSharpTypePrinter(null); |
|
typePrinter.PushContext(TypePrinterContextKind.Native); |
|
ctx.Return.Write("new {0}()", specialization.Visit(typePrinter)); |
|
} |
|
|
|
public override void CSharpMarshalToManaged(CSharpMarshalContext ctx) |
|
{ |
|
ctx.Return.Write(ctx.ReturnVarName); |
|
} |
|
} |
|
|
|
[TypeMap("TypeMappedWithOperator")] |
|
public class TypeMappedWithOperator : TypeMap |
|
{ |
|
public override Type CSharpSignatureType(TypePrinterContext ctx) |
|
{ |
|
// doesn't matter, we just need it to compile |
|
return new BuiltinType(PrimitiveType.Int); |
|
} |
|
|
|
public override void CSharpMarshalToNative(CSharpMarshalContext ctx) |
|
{ |
|
ctx.Return.Write(ctx.Parameter.Name); |
|
} |
|
|
|
public override void CSharpMarshalToManaged(CSharpMarshalContext ctx) |
|
{ |
|
ctx.Return.Write(ctx.ReturnVarName); |
|
} |
|
} |
|
|
|
[TypeMap("QString")] |
|
public class QString : TypeMap |
|
{ |
|
public override Type CSharpSignatureType(TypePrinterContext ctx) |
|
{ |
|
if (ctx.Kind == TypePrinterContextKind.Native) |
|
{ |
|
return new CustomType($@"global::CSharp.QString.{ |
|
Helpers.InternalStruct}{ |
|
(ctx.Type.IsAddress() ? "*" : string.Empty)}"); |
|
} |
|
return new CILType(typeof(string)); |
|
} |
|
|
|
public override void CSharpMarshalToNative(CSharpMarshalContext ctx) |
|
{ |
|
ctx.Return.Write(ctx.Parameter.Type.Desugar().IsAddress() ? |
|
"global::System.IntPtr.Zero" : "\"test\""); |
|
} |
|
|
|
public override void CSharpMarshalToManaged(CSharpMarshalContext ctx) |
|
{ |
|
ctx.Return.Write("\"test\""); |
|
} |
|
} |
|
|
|
#endregion |
|
} |
|
|
|
|