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.
201 lines
7.3 KiB
201 lines
7.3 KiB
using System.Linq; |
|
using CppSharp.AST; |
|
using CppSharp.Generators.CSharp; |
|
|
|
namespace CppSharp.Passes |
|
{ |
|
/// <summary> |
|
/// Checks for missing operator overloads required by C#. |
|
/// </summary> |
|
class CheckOperatorsOverloadsPass : TranslationUnitPass |
|
{ |
|
public override bool VisitClassDecl(Class @class) |
|
{ |
|
if (@class.CompleteDeclaration != null) |
|
return VisitClassDecl(@class.CompleteDeclaration as Class); |
|
|
|
if (!VisitDeclaration(@class)) |
|
return false; |
|
|
|
if (AlreadyVisited(@class)) |
|
return false; |
|
|
|
// Check for C++ operators that cannot be represented in C#. |
|
CheckInvalidOperators(@class); |
|
|
|
// The comparison operators, if overloaded, must be overloaded in pairs; |
|
// that is, if == is overloaded, != must also be overloaded. The reverse |
|
// is also true, and similar for < and >, and for <= and >=. |
|
|
|
HandleMissingOperatorOverloadPair(@class, CXXOperatorKind.EqualEqual, |
|
CXXOperatorKind.ExclaimEqual); |
|
|
|
HandleMissingOperatorOverloadPair(@class, CXXOperatorKind.Less, |
|
CXXOperatorKind.Greater); |
|
|
|
HandleMissingOperatorOverloadPair(@class, CXXOperatorKind.LessEqual, |
|
CXXOperatorKind.GreaterEqual); |
|
|
|
return false; |
|
} |
|
|
|
private void CheckInvalidOperators(Class @class) |
|
{ |
|
foreach (var @operator in @class.Operators) |
|
{ |
|
if (!IsValidOperatorOverload(@operator.OperatorKind)) |
|
{ |
|
Driver.Diagnostics.EmitError(DiagnosticId.InvalidOperatorOverload, |
|
"Invalid operator overload {0}::{1}", |
|
@class.OriginalName, @operator.OperatorKind); |
|
@operator.ExplicityIgnored = true; |
|
continue; |
|
} |
|
|
|
// Handle missing operator parameters |
|
if (@operator.IsStatic) |
|
@operator.Parameters = @operator.Parameters.Skip(1).ToList(); |
|
|
|
var type = new PointerType() |
|
{ |
|
QualifiedPointee = new QualifiedType(new TagType(@class)), |
|
Modifier = PointerType.TypeModifier.Pointer |
|
}; |
|
|
|
@operator.Parameters.Insert(0, new Parameter |
|
{ |
|
Name = Helpers.GeneratedIdentifier("op"), |
|
QualifiedType = new QualifiedType(type), |
|
Kind = ParameterKind.OperatorParameter |
|
}); |
|
} |
|
} |
|
|
|
static void HandleMissingOperatorOverloadPair(Class @class, CXXOperatorKind op1, |
|
CXXOperatorKind op2) |
|
{ |
|
int index; |
|
var missingKind = CheckMissingOperatorOverloadPair(@class, out index, op1, op2); |
|
|
|
if (missingKind == CXXOperatorKind.None) |
|
return; |
|
|
|
var existingKind = missingKind == op2 ? op1 : op2; |
|
|
|
// FIXME: We have to check for missing overloads per overload instance. |
|
foreach (var overload in @class.FindOperator(existingKind).ToList()) |
|
{ |
|
if (overload.Ignore) continue; |
|
|
|
var @params = overload.Parameters; |
|
|
|
bool isBuiltin; |
|
var method = new Method() |
|
{ |
|
Name = CSharpTextTemplate.GetOperatorIdentifier(missingKind, out isBuiltin), |
|
Namespace = @class, |
|
IsSynthetized = true, |
|
Kind = CXXMethodKind.Operator, |
|
OperatorKind = missingKind, |
|
ReturnType = overload.ReturnType, |
|
Parameters = @params |
|
}; |
|
|
|
@class.Methods.Insert(index, method); |
|
} |
|
} |
|
|
|
static CXXOperatorKind CheckMissingOperatorOverloadPair(Class @class, |
|
out int index, CXXOperatorKind op1, CXXOperatorKind op2) |
|
{ |
|
var first = @class.FindOperator(op1).ToList(); |
|
var second = @class.FindOperator(op2).ToList(); |
|
|
|
var hasFirst = first.Count > 0; |
|
var hasSecond = second.Count > 0; |
|
|
|
if (hasFirst && !hasSecond) |
|
{ |
|
index = @class.Methods.IndexOf(first.Last()); |
|
return op2; |
|
} |
|
|
|
if (hasSecond && !hasFirst) |
|
{ |
|
index = @class.Methods.IndexOf(second.First()); |
|
return op1; |
|
} |
|
|
|
index = 0; |
|
return CXXOperatorKind.None; |
|
} |
|
|
|
static bool IsValidOperatorOverload(CXXOperatorKind kind) |
|
{ |
|
// These follow the order described in MSDN (Overloadable Operators). |
|
|
|
switch (kind) |
|
{ |
|
// These unary operators can be overloaded |
|
case CXXOperatorKind.Plus: |
|
case CXXOperatorKind.Minus: |
|
case CXXOperatorKind.Exclaim: |
|
case CXXOperatorKind.Tilde: |
|
case CXXOperatorKind.PlusPlus: |
|
case CXXOperatorKind.MinusMinus: |
|
|
|
// These binary operators can be overloaded |
|
case CXXOperatorKind.Star: |
|
case CXXOperatorKind.Slash: |
|
case CXXOperatorKind.Percent: |
|
case CXXOperatorKind.Amp: |
|
case CXXOperatorKind.Pipe: |
|
case CXXOperatorKind.Caret: |
|
case CXXOperatorKind.LessLess: |
|
case CXXOperatorKind.GreaterGreater: |
|
|
|
// The comparison operators can be overloaded |
|
case CXXOperatorKind.EqualEqual: |
|
case CXXOperatorKind.ExclaimEqual: |
|
case CXXOperatorKind.Less: |
|
case CXXOperatorKind.Greater: |
|
case CXXOperatorKind.LessEqual: |
|
case CXXOperatorKind.GreaterEqual: |
|
return true; |
|
|
|
// Assignment operators cannot be overloaded |
|
case CXXOperatorKind.PlusEqual: |
|
case CXXOperatorKind.MinusEqual: |
|
case CXXOperatorKind.StarEqual: |
|
case CXXOperatorKind.SlashEqual: |
|
case CXXOperatorKind.PercentEqual: |
|
case CXXOperatorKind.AmpEqual: |
|
case CXXOperatorKind.PipeEqual: |
|
case CXXOperatorKind.CaretEqual: |
|
case CXXOperatorKind.LessLessEqual: |
|
case CXXOperatorKind.GreaterGreaterEqual: |
|
|
|
// The array indexing operator cannot be overloaded |
|
case CXXOperatorKind.Subscript: |
|
|
|
// The conditional logical operators cannot be overloaded |
|
case CXXOperatorKind.AmpAmp: |
|
case CXXOperatorKind.PipePipe: |
|
|
|
// These operators cannot be overloaded. |
|
case CXXOperatorKind.Equal: |
|
case CXXOperatorKind.Comma: |
|
case CXXOperatorKind.ArrowStar: |
|
case CXXOperatorKind.Arrow: |
|
case CXXOperatorKind.Call: |
|
case CXXOperatorKind.Conditional: |
|
case CXXOperatorKind.New: |
|
case CXXOperatorKind.Delete: |
|
case CXXOperatorKind.Array_New: |
|
case CXXOperatorKind.Array_Delete: |
|
default: |
|
return false; |
|
} |
|
} |
|
} |
|
}
|
|
|