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.
204 lines
6.4 KiB
204 lines
6.4 KiB
using System; |
|
using System.Linq; |
|
using System.Text; |
|
using System.IO; |
|
using System.Collections.Generic; |
|
using System.CodeDom; |
|
|
|
using Mono.VisualC.Interop; |
|
|
|
namespace Mono.VisualC.Code.Atoms { |
|
|
|
public class Method : CodeContainer { |
|
public struct Parameter { |
|
public string Name; |
|
public CppType Type; |
|
} |
|
|
|
public string Name { get; set; } |
|
public Access Access { get; set; } |
|
public bool IsVirtual { get; set; } |
|
public bool IsStatic { get; set; } |
|
public bool IsConst { get; set; } |
|
public bool IsConstructor { get; set; } |
|
public bool IsDestructor { get; set; } |
|
|
|
public CppType RetType { get; set; } |
|
public IList<Parameter> Parameters { get; set; } |
|
|
|
public Method (string name) |
|
{ |
|
Name = name; |
|
Parameters = new List<Parameter> (); |
|
} |
|
|
|
internal protected override object InsideCodeTypeDeclaration (CodeTypeDeclaration decl) |
|
{ |
|
if (decl.IsClass) { |
|
var method = CreateWrapperMethod (); |
|
decl.Members.Add (method); |
|
return method; |
|
|
|
} else if (decl.IsInterface) |
|
decl.Members.Add (CreateInterfaceMethod ()); |
|
|
|
return null; |
|
} |
|
|
|
internal protected override object InsideCodeStatementCollection (CodeStatementCollection stmts) |
|
{ |
|
List<CodeExpression> arguments = new List<CodeExpression> (); |
|
if (!IsStatic) |
|
arguments.Add (new CodeFieldReferenceExpression (new CodeThisReferenceExpression (), "Native")); |
|
|
|
foreach (var param in Parameters) { |
|
// FIXME: handle typenames |
|
if (param.Type.ElementType != CppTypes.Typename) { |
|
Type managedType = param.Type.ToManagedType (); |
|
if (managedType != null && managedType.IsByRef) { |
|
arguments.Add (new CodeDirectionExpression (FieldDirection.Ref, new CodeArgumentReferenceExpression (param.Name))); |
|
continue; |
|
} |
|
} |
|
arguments.Add (new CodeArgumentReferenceExpression (param.Name)); |
|
} |
|
|
|
|
|
// FIXME: Does just specifying the field name work for all code generators? |
|
var impl = new CodeFieldReferenceExpression { FieldName = "impl" }; |
|
var invoke = new CodeMethodInvokeExpression (impl, Name, arguments.ToArray ()); |
|
|
|
if (RetType.Equals (CppTypes.Void)) |
|
stmts.Add (invoke); |
|
else |
|
stmts.Add (new CodeMethodReturnStatement (invoke)); |
|
|
|
return null; |
|
} |
|
|
|
private CodeMemberMethod CreateInterfaceMethod () |
|
{ |
|
var method = new CodeMemberMethod { |
|
Name = this.Name, |
|
ReturnType = this.ReturnTypeReference |
|
}; |
|
|
|
if (IsVirtual) method.CustomAttributes.Add (new CodeAttributeDeclaration ("Virtual")); |
|
if (IsConstructor) method.CustomAttributes.Add (new CodeAttributeDeclaration ("Constructor")); |
|
if (IsDestructor) method.CustomAttributes.Add (new CodeAttributeDeclaration ("Destructor")); |
|
if (IsConst) method.CustomAttributes.Add (new CodeAttributeDeclaration ("Const")); |
|
|
|
if (IsStatic) |
|
method.CustomAttributes.Add (new CodeAttributeDeclaration ("Static")); |
|
else |
|
method.Parameters.Add (new CodeParameterDeclarationExpression (typeof (CppInstancePtr).Name, "this")); |
|
|
|
AddParameters (method, true); |
|
return method; |
|
} |
|
|
|
private CodeMemberMethod CreateWrapperMethod () |
|
{ |
|
CodeMemberMethod method; |
|
|
|
if (IsConstructor) |
|
method = new CodeConstructor { |
|
Name = FormattedName, |
|
Attributes = MemberAttributes.Public |
|
}; |
|
else if (IsDestructor) |
|
method = new CodeMemberMethod { |
|
Name = "Dispose", |
|
Attributes = MemberAttributes.Public |
|
}; |
|
else |
|
method = new CodeMemberMethod { |
|
Name = FormattedName, |
|
Attributes = MemberAttributes.Public, |
|
ReturnType = ReturnTypeReference |
|
}; |
|
|
|
if (IsStatic) |
|
method.Attributes |= MemberAttributes.Static; |
|
else if (!IsVirtual && !IsDestructor) |
|
// I'm only making methods that are virtual in C++ virtual in managed code. |
|
// I think it is the right thing to do because the consumer of the API might not |
|
// get the intended effect if the managed method is overridden and the native method is not. |
|
method.Attributes |= MemberAttributes.Final; |
|
else if (IsVirtual && !IsDestructor) |
|
method.CustomAttributes.Add (new CodeAttributeDeclaration ("OverrideNative")); |
|
|
|
AddParameters (method, false); |
|
return method; |
|
} |
|
|
|
public CodeTypeReference ReturnTypeReference { |
|
get { |
|
CodeTypeReference returnType; |
|
|
|
if (RetType.ElementType == CppTypes.Typename) |
|
returnType = new CodeTypeReference (RetType.ElementTypeName, CodeTypeReferenceOptions.GenericTypeParameter); |
|
else { |
|
Type managedType = RetType.ToManagedType (); |
|
if (managedType != null && managedType.IsByRef) |
|
returnType = new CodeTypeReference (typeof (IntPtr)); |
|
else if (managedType != null && managedType != typeof (ICppObject)) |
|
returnType = new CodeTypeReference (managedType); |
|
else |
|
returnType = RetType.TypeReference (); |
|
} |
|
|
|
return returnType; |
|
} |
|
} |
|
|
|
private void AddParameters (CodeMemberMethod method, bool includeMangleAttribute) |
|
{ |
|
foreach (var param in Parameters) { |
|
CodeParameterDeclarationExpression paramDecl; |
|
|
|
if (param.Type.ElementType == CppTypes.Typename) |
|
paramDecl = new CodeParameterDeclarationExpression (param.Type.ElementTypeName, param.Name); |
|
else { |
|
Type managedType = param.Type.ToManagedType (); |
|
if (managedType != null && managedType.IsByRef) |
|
paramDecl = new CodeParameterDeclarationExpression (managedType.GetElementType (), param.Name) { Direction = FieldDirection.Ref }; |
|
else if (managedType != null && managedType != typeof (ICppObject)) |
|
paramDecl = new CodeParameterDeclarationExpression (managedType, param.Name); |
|
else |
|
paramDecl = new CodeParameterDeclarationExpression (param.Type.TypeReference (), param.Name); |
|
} |
|
|
|
// FIXME: Only add MangleAs attribute if the managed type chosen would mangle differently by default |
|
string paramStr = param.Type.ToString (); |
|
if (includeMangleAttribute && !IsVirtual && !paramStr.Equals (string.Empty)) |
|
paramDecl.CustomAttributes.Add (new CodeAttributeDeclaration ("MangleAs", new CodeAttributeArgument (new CodePrimitiveExpression (paramStr)))); |
|
|
|
method.Parameters.Add (paramDecl); |
|
} |
|
} |
|
|
|
public string FormattedName { |
|
get { |
|
string upper = Name.ToUpper (); |
|
StringBuilder sb = new StringBuilder (Name.Length); |
|
|
|
for (int i = 0; i < Name.Length; i++) { |
|
if (i == 0) |
|
sb.Append (upper [0]); |
|
else if (Name [i] == '_') |
|
sb.Append (upper [++i]); |
|
else |
|
sb.Append (Name [i]); |
|
} |
|
return sb.ToString (); |
|
} |
|
} |
|
|
|
public override void Write (TextWriter writer) |
|
{ |
|
throw new NotImplementedException (); |
|
} |
|
} |
|
} |
|
|
|
|