Tools and libraries to glue C/C++ APIs to high-level languages
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

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;
}
}
}
}