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.
867 lines
28 KiB
867 lines
28 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.Linq; |
|
using CppSharp.AST; |
|
using CppSharp.AST.Extensions; |
|
using CppSharp.Generators.CSharp; |
|
using CppSharp.Types; |
|
|
|
namespace CppSharp.Generators.CLI |
|
{ |
|
/// <summary> |
|
/// Generates C++/CLI header files. |
|
/// </summary> |
|
public class CLIHeadersTemplate : CLITextTemplate |
|
{ |
|
public override string FileExtension { get { return "h"; } } |
|
|
|
public CLIHeadersTemplate(Driver driver, IEnumerable<TranslationUnit> units) |
|
: base(driver, units) |
|
{ |
|
} |
|
|
|
public override void Process() |
|
{ |
|
PushBlock(BlockKind.Header); |
|
PopBlock(); |
|
|
|
PushBlock(CLIBlockKind.Includes); |
|
WriteLine("#pragma once"); |
|
NewLine(); |
|
|
|
if (Options.OutputInteropIncludes) |
|
WriteLine("#include \"CppSharp.h\""); |
|
|
|
// Generate #include forward references. |
|
PushBlock(CLIBlockKind.IncludesForwardReferences); |
|
WriteLine("#include <{0}>", TranslationUnit.IncludePath); |
|
GenerateIncludeForwardRefs(); |
|
PopBlock(NewLineKind.BeforeNextBlock); |
|
PopBlock(NewLineKind.Always); |
|
|
|
// Generate namespace for forward references. |
|
PushBlock(CLIBlockKind.ForwardReferences); |
|
GenerateForwardRefs(); |
|
PopBlock(NewLineKind.BeforeNextBlock); |
|
|
|
GenerateNamespace(TranslationUnit); |
|
|
|
PushBlock(BlockKind.Footer); |
|
PopBlock(); |
|
} |
|
|
|
public void GenerateIncludeForwardRefs() |
|
{ |
|
var typeReferenceCollector = new CLITypeReferenceCollector(Driver.TypeDatabase, |
|
Driver.Options); |
|
typeReferenceCollector.Process(TranslationUnit, filterNamespaces: false); |
|
|
|
var includes = new SortedSet<string>(StringComparer.InvariantCulture); |
|
|
|
foreach (var typeRef in typeReferenceCollector.TypeReferences) |
|
{ |
|
if (typeRef.Include.TranslationUnit == TranslationUnit) |
|
continue; |
|
|
|
if (typeRef.Include.File == TranslationUnit.FileName) |
|
continue; |
|
|
|
var include = typeRef.Include; |
|
var unit = include.TranslationUnit; |
|
|
|
if (unit != null && !unit.IsDeclared) |
|
continue; |
|
|
|
if(!string.IsNullOrEmpty(include.File) && include.InHeader) |
|
includes.Add(include.ToString()); |
|
} |
|
|
|
foreach (var include in includes) |
|
WriteLine(include); |
|
} |
|
|
|
private Namespace FindCreateNamespace(Namespace @namespace, Declaration decl) |
|
{ |
|
if (decl.Namespace is TranslationUnit) |
|
return @namespace; |
|
|
|
var childNamespaces = decl.Namespace.GatherParentNamespaces(); |
|
var currentNamespace = @namespace; |
|
|
|
foreach (var child in childNamespaces) |
|
currentNamespace = currentNamespace.FindCreateNamespace(child.Name); |
|
|
|
return currentNamespace; |
|
} |
|
|
|
public Namespace ConvertForwardReferencesToNamespaces( |
|
IEnumerable<CLITypeReference> typeReferences) |
|
{ |
|
// Create a new tree of namespaces out of the type references found. |
|
var rootNamespace = new TranslationUnit(); |
|
rootNamespace.Module = TranslationUnit.Module; |
|
|
|
var sortedRefs = typeReferences.ToList(); |
|
sortedRefs.Sort((ref1, ref2) => |
|
string.CompareOrdinal(ref1.FowardReference, ref2.FowardReference)); |
|
|
|
var forwardRefs = new SortedSet<string>(); |
|
|
|
foreach (var typeRef in sortedRefs) |
|
{ |
|
if (string.IsNullOrWhiteSpace(typeRef.FowardReference)) |
|
continue; |
|
|
|
var declaration = typeRef.Declaration; |
|
if (!(declaration.Namespace is Namespace)) |
|
continue; |
|
|
|
if (!forwardRefs.Add(typeRef.FowardReference)) |
|
continue; |
|
|
|
if (typeRef.Include.InHeader) |
|
continue; |
|
|
|
var @namespace = FindCreateNamespace(rootNamespace, declaration); |
|
@namespace.TypeReferences.Add(typeRef); |
|
} |
|
|
|
return rootNamespace; |
|
} |
|
|
|
public void GenerateForwardRefs() |
|
{ |
|
var typeReferenceCollector = new CLITypeReferenceCollector(Driver.TypeDatabase, |
|
Driver.Options); |
|
typeReferenceCollector.Process(TranslationUnit); |
|
|
|
var typeReferences = typeReferenceCollector.TypeReferences; |
|
var @namespace = ConvertForwardReferencesToNamespaces(typeReferences); |
|
|
|
GenerateNamespace(@namespace); |
|
} |
|
|
|
public void GenerateDeclContext(DeclarationContext decl) |
|
{ |
|
// Generate all the type references for the module. |
|
foreach (var typeRef in decl.TypeReferences) |
|
{ |
|
WriteLine(typeRef.FowardReference); |
|
} |
|
|
|
// Generate all the enum declarations for the module. |
|
foreach (var @enum in decl.Enums) |
|
{ |
|
if (!@enum.IsGenerated || @enum.IsIncomplete) |
|
continue; |
|
|
|
PushBlock(CLIBlockKind.Enum, @enum); |
|
GenerateEnum(@enum); |
|
PopBlock(NewLineKind.BeforeNextBlock); |
|
} |
|
|
|
// Generate all the typedef declarations for the module. |
|
GenerateTypedefs(decl); |
|
|
|
// Generate all the struct/class declarations for the module. |
|
foreach (var @class in decl.Classes) |
|
{ |
|
if (!@class.IsGenerated || @class.IsIncomplete) |
|
continue; |
|
|
|
if (@class.IsOpaque) |
|
continue; |
|
|
|
PushBlock(CLIBlockKind.Class, @class); |
|
GenerateClass(@class); |
|
PopBlock(NewLineKind.BeforeNextBlock); |
|
} |
|
|
|
if (decl.HasFunctions) |
|
GenerateFunctions(decl); |
|
|
|
foreach (var childNamespace in decl.Namespaces) |
|
GenerateNamespace(childNamespace); |
|
} |
|
|
|
public void GenerateNamespace(Namespace @namespace) |
|
{ |
|
var isTopLevel = @namespace is TranslationUnit; |
|
var generateNamespace = !isTopLevel || Options.GenerateLibraryNamespace; |
|
|
|
if (generateNamespace) |
|
{ |
|
PushBlock(CLIBlockKind.Namespace, @namespace); |
|
WriteLine("namespace {0}", isTopLevel |
|
? @namespace.TranslationUnit.Module.OutputNamespace |
|
: @namespace.Name); |
|
WriteStartBraceIndent(); |
|
} |
|
|
|
GenerateDeclContext(@namespace); |
|
|
|
if (generateNamespace) |
|
{ |
|
WriteCloseBraceIndent(); |
|
PopBlock(NewLineKind.BeforeNextBlock); |
|
} |
|
} |
|
|
|
public void GenerateTypedefs(DeclarationContext decl) |
|
{ |
|
foreach (var typedef in decl.Typedefs) |
|
{ |
|
if (!typedef.IsGenerated) |
|
continue; |
|
|
|
GenerateTypedef(typedef); |
|
} |
|
} |
|
|
|
public void GenerateFunctions(DeclarationContext decl) |
|
{ |
|
PushBlock(CLIBlockKind.FunctionsClass); |
|
|
|
WriteLine("public ref class {0}", TranslationUnit.FileNameWithoutExtension); |
|
WriteLine("{"); |
|
WriteLine("public:"); |
|
PushIndent(); |
|
|
|
// Generate all the function declarations for the module. |
|
foreach (var function in decl.Functions) |
|
{ |
|
GenerateFunction(function); |
|
} |
|
|
|
PopIndent(); |
|
WriteLine("};"); |
|
|
|
PopBlock(NewLineKind.BeforeNextBlock); |
|
} |
|
|
|
public void GenerateClass(Class @class) |
|
{ |
|
if (!@class.IsGenerated || @class.IsIncomplete) |
|
return; |
|
|
|
GenerateDeclarationCommon(@class); |
|
|
|
if (GenerateClassProlog(@class)) |
|
return; |
|
|
|
// Process the nested types. |
|
PushIndent(); |
|
GenerateDeclContext(@class); |
|
PopIndent(); |
|
|
|
var nativeType = string.Format("::{0}*", @class.QualifiedOriginalName); |
|
|
|
if (CLIGenerator.ShouldGenerateClassNativeField(@class)) |
|
GenerateClassNativeField(@class, nativeType); |
|
|
|
GenerateClassConstructors(@class, nativeType); |
|
|
|
GenerateClassProperties(@class); |
|
|
|
GenerateClassEvents(@class); |
|
GenerateClassMethods(@class.Methods); |
|
|
|
if (Options.GenerateFunctionTemplates) |
|
GenerateClassGenericMethods(@class); |
|
|
|
GenerateClassVariables(@class); |
|
|
|
if (CLIGenerator.ShouldGenerateClassNativeField(@class)) |
|
{ |
|
PushBlock(CLIBlockKind.AccessSpecifier); |
|
WriteLine("protected:"); |
|
PopBlock(NewLineKind.IfNotEmpty); |
|
|
|
PushBlock(CLIBlockKind.Fields); |
|
WriteLineIndent("bool {0};", Helpers.OwnsNativeInstanceIdentifier); |
|
PopBlock(); |
|
} |
|
|
|
PushBlock(CLIBlockKind.AccessSpecifier); |
|
WriteLine("private:"); |
|
var accBlock = PopBlock(NewLineKind.IfNotEmpty); |
|
|
|
PushBlock(CLIBlockKind.Fields); |
|
GenerateClassFields(@class); |
|
var fieldsBlock = PopBlock(); |
|
|
|
accBlock.CheckGenerate = () => !fieldsBlock.IsEmpty; |
|
|
|
WriteLine("};"); |
|
} |
|
|
|
public void GenerateClassNativeField(Class @class, string nativeType) |
|
{ |
|
WriteLineIndent("property {0} NativePtr;", nativeType); |
|
|
|
PushIndent(); |
|
WriteLine("property System::IntPtr {0}", Helpers.InstanceIdentifier); |
|
WriteStartBraceIndent(); |
|
WriteLine("virtual System::IntPtr get();"); |
|
WriteLine("virtual void set(System::IntPtr instance);"); |
|
WriteCloseBraceIndent(); |
|
NewLine(); |
|
|
|
PopIndent(); |
|
} |
|
|
|
public void GenerateClassGenericMethods(Class @class) |
|
{ |
|
var printer = TypePrinter; |
|
var oldCtx = printer.Context; |
|
|
|
PushIndent(); |
|
foreach (var template in @class.Templates) |
|
{ |
|
if (!template.IsGenerated) continue; |
|
|
|
var functionTemplate = template as FunctionTemplate; |
|
if (functionTemplate == null) continue; |
|
|
|
PushBlock(CLIBlockKind.Template); |
|
|
|
var function = functionTemplate.TemplatedFunction; |
|
|
|
var typeCtx = new CLITypePrinterContext() |
|
{ |
|
Kind = TypePrinterContextKind.Template, |
|
Declaration = template |
|
}; |
|
|
|
printer.Context = typeCtx; |
|
|
|
var typePrinter = new CLITypePrinter(Driver, typeCtx); |
|
var retType = function.ReturnType.Type.Visit(typePrinter, |
|
function.ReturnType.Qualifiers); |
|
|
|
var typeNames = ""; |
|
var paramNames = template.Parameters.Select(param => param.Name).ToList(); |
|
if (paramNames.Any()) |
|
typeNames = "typename " + string.Join(", typename ", paramNames); |
|
|
|
Write("generic<{0}>", typeNames); |
|
|
|
// Process the generic type constraints |
|
var constraints = new List<string>(); |
|
foreach (var param in template.Parameters.OfType<TypeTemplateParameter>()) |
|
{ |
|
if (string.IsNullOrWhiteSpace(param.Constraint)) |
|
continue; |
|
constraints.Add(string.Format("{0} : {1}", param.Name, |
|
param.Constraint)); |
|
} |
|
|
|
if (constraints.Any()) |
|
Write(" where {0}", string.Join(", ", constraints)); |
|
|
|
NewLine(); |
|
|
|
WriteLine("{0} {1}({2});", retType, function.Name, |
|
GenerateParametersList(function.Parameters)); |
|
|
|
PopBlock(NewLineKind.BeforeNextBlock); |
|
} |
|
PopIndent(); |
|
|
|
printer.Context = oldCtx; |
|
} |
|
|
|
public void GenerateClassConstructors(Class @class, string nativeType) |
|
{ |
|
if (@class.IsStatic) |
|
return; |
|
|
|
PushIndent(); |
|
|
|
// Output a default constructor that takes the native pointer. |
|
WriteLine("{0}({1} native);", @class.Name, nativeType); |
|
WriteLine("static {0}^ {1}(::System::IntPtr native);", |
|
@class.Name, Helpers.CreateInstanceIdentifier); |
|
|
|
foreach (var ctor in @class.Constructors) |
|
{ |
|
if (ASTUtils.CheckIgnoreMethod(ctor, Options)) |
|
continue; |
|
|
|
// C++/CLI does not allow special member funtions for value types. |
|
if (@class.IsValueType && ctor.IsCopyConstructor) |
|
continue; |
|
|
|
GenerateMethod(ctor); |
|
} |
|
|
|
if (@class.IsRefType) |
|
{ |
|
var destructor = @class.Destructors |
|
.FirstOrDefault(d => d.Parameters.Count == 0 && d.Access == AccessSpecifier.Public); |
|
if (destructor != null) |
|
{ |
|
GenerateClassDestructor(@class); |
|
if (Options.GenerateFinalizers) |
|
GenerateClassFinalizer(@class); |
|
} |
|
} |
|
|
|
PopIndent(); |
|
} |
|
|
|
private void GenerateClassDestructor(Class @class) |
|
{ |
|
PushBlock(CLIBlockKind.Destructor); |
|
WriteLine("~{0}();", @class.Name); |
|
PopBlock(NewLineKind.BeforeNextBlock); |
|
} |
|
|
|
private void GenerateClassFinalizer(Class @class) |
|
{ |
|
PushBlock(CLIBlockKind.Finalizer); |
|
WriteLine("!{0}();", @class.Name); |
|
PopBlock(NewLineKind.BeforeNextBlock); |
|
} |
|
|
|
public void GenerateClassFields(Class @class) |
|
{ |
|
// Handle the case of struct (value-type) inheritance by adding the base |
|
// properties to the managed value subtypes. |
|
if (@class.IsValueType) |
|
{ |
|
foreach (var @base in @class.Bases.Where(b => b.IsClass && b.Class.IsDeclared)) |
|
{ |
|
GenerateClassFields(@base.Class); |
|
} |
|
} |
|
|
|
PushIndent(); |
|
// check for value types because some of the ignored fields may back properties; |
|
// not the case for ref types because the NativePtr pattern is used there |
|
foreach (var field in @class.Fields.Where(f => !ASTUtils.CheckIgnoreField(f))) |
|
{ |
|
var property = @class.Properties.FirstOrDefault(p => p.Field == field); |
|
if (property != null && !property.IsInRefTypeAndBackedByValueClassField()) |
|
{ |
|
GenerateField(@class, field); |
|
} |
|
} |
|
PopIndent(); |
|
} |
|
|
|
private void GenerateField(Class @class, Field field) |
|
{ |
|
PushBlock(CLIBlockKind.Field, field); |
|
|
|
GenerateDeclarationCommon(field); |
|
if (@class.IsUnion) |
|
WriteLine("[System::Runtime::InteropServices::FieldOffset({0})]", |
|
@class.Layout.Fields.Single(f => f.FieldPtr == field.OriginalPtr).Offset); |
|
WriteLine("{0} {1};", field.Type, field.Name); |
|
|
|
PopBlock(); |
|
} |
|
|
|
public void GenerateClassEvents(Class @class) |
|
{ |
|
foreach (var @event in @class.Events) |
|
{ |
|
if (!@event.IsGenerated) continue; |
|
|
|
var cppTypePrinter = new CppTypePrinter(); |
|
var cppArgs = cppTypePrinter.VisitParameters(@event.Parameters, hasNames: true); |
|
|
|
WriteLine("private:"); |
|
PushIndent(); |
|
|
|
var delegateName = string.Format("_{0}Delegate", @event.Name); |
|
WriteLine("delegate void {0}({1});", delegateName, cppArgs); |
|
WriteLine("{0}^ {0}Instance;", delegateName); |
|
|
|
WriteLine("void _{0}Raise({1});", @event.Name, cppArgs); |
|
WriteLine("{0} _{1};", @event.Type, @event.Name); |
|
|
|
PopIndent(); |
|
WriteLine("public:"); |
|
PushIndent(); |
|
|
|
WriteLine("event {0} {1}", @event.Type, @event.Name); |
|
WriteStartBraceIndent(); |
|
|
|
WriteLine("void add({0} evt);", @event.Type); |
|
WriteLine("void remove({0} evt);", @event.Type); |
|
|
|
var cliTypePrinter = new CLITypePrinter(Driver); |
|
var cliArgs = cliTypePrinter.VisitParameters(@event.Parameters, hasNames: true); |
|
|
|
WriteLine("void raise({0});", cliArgs); |
|
WriteCloseBraceIndent(); |
|
PopIndent(); |
|
} |
|
} |
|
|
|
public void GenerateClassMethods(List<Method> methods) |
|
{ |
|
if (methods.Count == 0) |
|
return; |
|
|
|
PushIndent(); |
|
|
|
var @class = (Class) methods[0].Namespace; |
|
|
|
if (@class.IsValueType) |
|
foreach (var @base in @class.Bases.Where(b => b.IsClass && !b.Class.Ignore)) |
|
GenerateClassMethods(@base.Class.Methods.Where(m => !m.IsOperator).ToList()); |
|
|
|
var staticMethods = new List<Method>(); |
|
foreach (var method in methods) |
|
{ |
|
if (ASTUtils.CheckIgnoreMethod(method, Options)) |
|
continue; |
|
|
|
if (method.IsConstructor) |
|
continue; |
|
|
|
if (method.IsStatic) |
|
{ |
|
staticMethods.Add(method); |
|
continue; |
|
} |
|
|
|
GenerateMethod(method); |
|
} |
|
|
|
foreach(var method in staticMethods) |
|
GenerateMethod(method); |
|
|
|
PopIndent(); |
|
} |
|
|
|
public void GenerateClassVariables(Class @class) |
|
{ |
|
PushIndent(); |
|
|
|
foreach(var variable in @class.Variables) |
|
{ |
|
if (!variable.IsGenerated) continue; |
|
|
|
if (variable.Access != AccessSpecifier.Public) |
|
continue; |
|
|
|
var type = variable.Type; |
|
|
|
PushBlock(CLIBlockKind.Variable); |
|
|
|
WriteLine("static property {0} {1}", type, variable.Name); |
|
|
|
WriteStartBraceIndent(); |
|
|
|
WriteLine("{0} get();", type); |
|
|
|
var arrayType = type as ArrayType; |
|
var qualifiedType = arrayType != null ? arrayType.QualifiedType : variable.QualifiedType; |
|
if (!qualifiedType.Qualifiers.IsConst) |
|
WriteLine("void set({0});", type); |
|
|
|
WriteCloseBraceIndent(); |
|
|
|
PopBlock(NewLineKind.BeforeNextBlock); |
|
} |
|
|
|
PopIndent(); |
|
} |
|
|
|
public bool GenerateClassProlog(Class @class) |
|
{ |
|
if (@class.IsUnion) |
|
WriteLine("[System::Runtime::InteropServices::StructLayout({0})]", |
|
"System::Runtime::InteropServices::LayoutKind::Explicit"); |
|
|
|
// Nested types cannot have visibility modifiers in C++/CLI. |
|
var isTopLevel = @class.Namespace is TranslationUnit || |
|
@class.Namespace is Namespace; |
|
if (isTopLevel) |
|
Write("public "); |
|
|
|
Write(@class.IsValueType ? "value struct " : "ref class "); |
|
|
|
Write("{0}", @class.Name); |
|
|
|
if (@class.IsStatic) |
|
Write(" abstract sealed"); |
|
|
|
if (@class.IsOpaque) |
|
{ |
|
WriteLine(";"); |
|
return true; |
|
} |
|
|
|
if (!@class.IsStatic) |
|
{ |
|
if (@class.HasRefBase()) |
|
Write(" : {0}", QualifiedIdentifier(@class.Bases[0].Class)); |
|
else if (@class.IsRefType) |
|
Write(" : ICppInstance"); |
|
} |
|
|
|
NewLine(); |
|
WriteLine("{"); |
|
WriteLine("public:"); |
|
NewLine(); |
|
|
|
return false; |
|
} |
|
|
|
public void GenerateClassProperties(Class @class) |
|
{ |
|
// Handle the case of struct (value-type) inheritance by adding the base |
|
// properties to the managed value subtypes. |
|
if (@class.IsValueType) |
|
{ |
|
foreach (var @base in @class.Bases.Where(b => b.IsClass && b.Class.IsDeclared)) |
|
{ |
|
GenerateClassProperties(@base.Class); |
|
} |
|
} |
|
|
|
PushIndent(); |
|
foreach (var prop in @class.Properties.Where(prop => !ASTUtils.CheckIgnoreProperty(prop))) |
|
{ |
|
if (prop.IsInRefTypeAndBackedByValueClassField()) |
|
{ |
|
GenerateField(@class, prop.Field); |
|
continue; |
|
} |
|
|
|
GenerateDeclarationCommon(prop); |
|
GenerateProperty(prop); |
|
} |
|
PopIndent(); |
|
} |
|
|
|
public void GenerateIndexer(Property property) |
|
{ |
|
var type = property.QualifiedType.Visit(TypePrinter); |
|
var getter = property.GetMethod; |
|
var indexParameter = getter.Parameters[0]; |
|
var indexParameterType = indexParameter.QualifiedType.Visit(TypePrinter); |
|
|
|
WriteLine("property {0} default[{1}]", type, indexParameterType); |
|
WriteStartBraceIndent(); |
|
|
|
if (property.HasGetter) |
|
WriteLine("{0} get({1} {2});", type, indexParameterType, indexParameter.Name); |
|
|
|
if (property.HasSetter) |
|
WriteLine("void set({1} {2}, {0} value);", type, indexParameterType, indexParameter.Name); |
|
|
|
WriteCloseBraceIndent(); |
|
} |
|
|
|
public void GenerateProperty(Property property) |
|
{ |
|
if (!(property.HasGetter || property.HasSetter)) |
|
return; |
|
|
|
PushBlock(CLIBlockKind.Property, property); |
|
var type = property.QualifiedType.Visit(TypePrinter); |
|
|
|
if (property.IsStatic) |
|
Write("static "); |
|
|
|
if (property.IsIndexer) |
|
{ |
|
GenerateIndexer(property); |
|
} |
|
else |
|
{ |
|
WriteLine("property {0} {1}", type, property.Name); |
|
WriteStartBraceIndent(); |
|
|
|
if (property.HasGetter) |
|
WriteLine("{0} get();", type); |
|
|
|
if (property.HasSetter) |
|
WriteLine("void set({0});", type); |
|
|
|
WriteCloseBraceIndent(); |
|
} |
|
|
|
PopBlock(NewLineKind.BeforeNextBlock); |
|
} |
|
|
|
public void GenerateMethod(Method method) |
|
{ |
|
if (ASTUtils.CheckIgnoreMethod(method, Options)) return; |
|
|
|
PushBlock(CLIBlockKind.Method, method); |
|
|
|
GenerateDeclarationCommon(method); |
|
|
|
if ((method.IsVirtual || method.IsOverride) && !method.IsOperator) |
|
Write("virtual "); |
|
|
|
var isBuiltinOperator = method.IsOperator && |
|
Operators.IsBuiltinOperator(method.OperatorKind); |
|
|
|
if (method.IsStatic || isBuiltinOperator) |
|
Write("static "); |
|
|
|
if (method.OperatorKind == CXXOperatorKind.ExplicitConversion) |
|
Write("explicit "); |
|
|
|
if (method.IsConstructor || method.IsDestructor || |
|
method.OperatorKind == CXXOperatorKind.Conversion || |
|
method.OperatorKind == CXXOperatorKind.ExplicitConversion) |
|
Write("{0}(", GetMethodName(method)); |
|
else |
|
Write("{0} {1}(", method.ReturnType, method.Name); |
|
|
|
GenerateMethodParameters(method); |
|
|
|
Write(")"); |
|
|
|
if (method.IsOverride) |
|
{ |
|
if (method.Access == AccessSpecifier.Private) |
|
Write(" sealed"); |
|
Write(" override"); |
|
} |
|
|
|
WriteLine(";"); |
|
|
|
if (method.OperatorKind == CXXOperatorKind.EqualEqual) |
|
{ |
|
GenerateEquals(method, (Class) method.Namespace); |
|
} |
|
|
|
PopBlock(NewLineKind.BeforeNextBlock); |
|
} |
|
|
|
private void GenerateEquals(Function method, Class @class) |
|
{ |
|
Class leftHandSide; |
|
Class rightHandSide; |
|
if (method.Parameters[0].Type.SkipPointerRefs().TryGetClass(out leftHandSide) && |
|
leftHandSide.OriginalPtr == @class.OriginalPtr && |
|
method.Parameters[1].Type.SkipPointerRefs().TryGetClass(out rightHandSide) && |
|
rightHandSide.OriginalPtr == @class.OriginalPtr) |
|
{ |
|
NewLine(); |
|
WriteLine("virtual bool Equals(::System::Object^ obj) override;"); |
|
} |
|
} |
|
|
|
public bool GenerateTypedef(TypedefDecl typedef) |
|
{ |
|
if (!typedef.IsGenerated) |
|
return false; |
|
|
|
FunctionType function; |
|
if (typedef.Type.IsPointerTo(out function)) |
|
{ |
|
PushBlock(CLIBlockKind.Typedef, typedef); |
|
GenerateDeclarationCommon(typedef); |
|
|
|
var insideClass = typedef.Namespace is Class; |
|
|
|
var attributedType = typedef.Type.GetPointee() as AttributedType; |
|
if (attributedType != null) |
|
{ |
|
var equivalentFunctionType = attributedType.Equivalent.Type as FunctionType; |
|
var callingConvention = equivalentFunctionType.CallingConvention.ToInteropCallConv(); |
|
if (callingConvention != System.Runtime.InteropServices.CallingConvention.Winapi) |
|
{ |
|
WriteLine("[{0}({1}::{2})] ", |
|
"System::Runtime::InteropServices::UnmanagedFunctionPointer", |
|
"System::Runtime::InteropServices::CallingConvention", |
|
callingConvention); |
|
} |
|
} |
|
|
|
WriteLine("{0}{1};", |
|
!insideClass ? "public " : "", |
|
string.Format(TypePrinter.VisitDelegate(function), |
|
typedef.Name)); |
|
PopBlock(NewLineKind.BeforeNextBlock); |
|
|
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
public void GenerateFunction(Function function) |
|
{ |
|
if (!function.IsGenerated) |
|
return; |
|
|
|
PushBlock(CLIBlockKind.Function, function); |
|
|
|
GenerateDeclarationCommon(function); |
|
|
|
var retType = function.ReturnType.ToString(); |
|
Write("static {0} {1}(", retType, function.Name); |
|
|
|
Write(GenerateParametersList(function.Parameters)); |
|
|
|
WriteLine(");"); |
|
|
|
PopBlock(); |
|
} |
|
|
|
public void GenerateEnum(Enumeration @enum) |
|
{ |
|
if (!@enum.IsGenerated || @enum.IsIncomplete) |
|
return; |
|
|
|
PushBlock(CLIBlockKind.Enum, @enum); |
|
|
|
GenerateDeclarationCommon(@enum); |
|
|
|
if (@enum.Modifiers.HasFlag(Enumeration.EnumModifiers.Flags)) |
|
WriteLine("[System::Flags]"); |
|
|
|
// A nested class cannot have an assembly access specifier as part |
|
// of its declaration. |
|
if (@enum.Namespace is Namespace) |
|
Write("public "); |
|
|
|
Write("enum struct {0}", @enum.Name); |
|
|
|
var typeName = TypePrinter.VisitPrimitiveType(@enum.BuiltinType.Type, |
|
new TypeQualifiers()); |
|
|
|
if (@enum.BuiltinType.Type != PrimitiveType.Int) |
|
WriteLine(" : {0}", typeName); |
|
else |
|
NewLine(); |
|
|
|
WriteLine("{"); |
|
|
|
PushIndent(); |
|
foreach (var item in @enum.Items) |
|
{ |
|
PushBlock(CLIBlockKind.EnumItem); |
|
|
|
GenerateInlineSummary(item.Comment); |
|
if (item.ExplicitValue) |
|
Write(String.Format("{0} = {1}", item.Name, |
|
@enum.GetItemValueAsString(item))); |
|
else |
|
Write(String.Format("{0}", item.Name)); |
|
|
|
if (item != @enum.Items.Last()) |
|
WriteLine(","); |
|
|
|
PopBlock(NewLineKind.Never); |
|
} |
|
PopIndent(); |
|
|
|
WriteLine("};"); |
|
|
|
PopBlock(NewLineKind.BeforeNextBlock); |
|
} |
|
} |
|
}
|
|
|