mirror of https://github.com/mono/CppSharp.git
4 changed files with 277 additions and 0 deletions
@ -0,0 +1,170 @@ |
|||||||
|
using System.Linq; |
||||||
|
|
||||||
|
namespace Cxxi.Passes |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Checks for missing operator overloads required by C#.
|
||||||
|
/// </summary>
|
||||||
|
class CheckOperatorsOverloadsPass : TranslationUnitPass |
||||||
|
{ |
||||||
|
public override bool VisitClassDecl(Class @class) |
||||||
|
{ |
||||||
|
// Check for C++ operators that cannot be represented in C#.
|
||||||
|
foreach (var @operator in @class.Operators) |
||||||
|
{ |
||||||
|
if (!IsValidOperatorOverload(@operator.OperatorKind)) |
||||||
|
{ |
||||||
|
Driver.Diagnostics.EmitError(DiagnosticId.InvalidOperatorOverload, |
||||||
|
"invalid operator overload"); |
||||||
|
@operator.ExplicityIgnored = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 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; |
||||||
|
} |
||||||
|
|
||||||
|
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; |
||||||
|
|
||||||
|
var overload = @class.FindOperator(existingKind).First(); |
||||||
|
var @params = overload.Parameters; |
||||||
|
|
||||||
|
if (overload.IsStatic) |
||||||
|
@params = @params.Skip(1).ToList(); |
||||||
|
|
||||||
|
var method = new Method() |
||||||
|
{ |
||||||
|
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); |
||||||
|
var second = @class.FindOperator(op2); |
||||||
|
|
||||||
|
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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static class CheckOperatorsOverloadsExtensions |
||||||
|
{ |
||||||
|
public static void CheckOperatorOverloads(this PassBuilder builder) |
||||||
|
{ |
||||||
|
var pass = new CheckOperatorsOverloadsPass(); |
||||||
|
builder.AddPass(pass); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue