@ -1,102 +1,102 @@
@@ -1,102 +1,102 @@
using System.Linq ;
using CppSharp.AST ;
using CppSharp.AST.Extensions ;
using CppSharp.Generators ;
namespace CppSharp.Passes
{
/// <summary>
/// Checks for missing operator overloads required by C#.
/// </summary>
class CheckOperatorsOverloadsPass : TranslationUnitPass
{
public CheckOperatorsOverloadsPass ( )
{
ClearVisitedDeclarations = false ;
}
public override bool VisitClassDecl ( Class @class )
{
if ( @class . CompleteDeclaration ! = null )
return VisitClassDecl ( @class . CompleteDeclaration as Class ) ;
if ( ! VisitDeclarationContext ( @class ) )
return false ;
// Check for C++ operators that cannot be represented in C#.
CheckInvalidOperators ( @class ) ;
if ( Driver . Options . IsCSharpGenerator )
{
// 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 . Where ( o = > o . IsGenerated ) )
{
if ( ! IsValidOperatorOverload ( @operator ) )
{
Driver . Diagnostics . Debug ( DiagnosticId . InvalidOperatorOverload ,
"Invalid operator overload {0}::{1}" ,
@class . OriginalName , @operator . OperatorKind ) ;
@operator . ExplicityIgnored = true ;
continue ;
}
if ( @operator . SynthKind = = FunctionSynthKind . NonMemberOperator )
continue ;
if ( @operator . OperatorKind = = CXXOperatorKind . Subscript )
{
CreateIndexer ( @class , @operator ) ;
}
else
{
// 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 . LVReference
} ;
@operator . Parameters . Insert ( 0 , new Parameter
{
Name = Generator . GeneratedIdentifier ( "op" ) ,
QualifiedType = new QualifiedType ( type ) ,
Kind = ParameterKind . OperatorParameter
} ) ;
}
}
}
void CreateIndexer ( Class @class , Method @operator )
{
var property = new Property
{
Name = "Item" ,
QualifiedType = @operator . ReturnType ,
Access = @operator . Access ,
Namespace = @class ,
GetMethod = @operator
} ;
using System.Linq ;
using CppSharp.AST ;
using CppSharp.AST.Extensions ;
using CppSharp.Generators ;
namespace CppSharp.Passes
{
/// <summary>
/// Checks for missing operator overloads required by C#.
/// </summary>
class CheckOperatorsOverloadsPass : TranslationUnitPass
{
public CheckOperatorsOverloadsPass ( )
{
ClearVisitedDeclarations = false ;
}
public override bool VisitClassDecl ( Class @class )
{
if ( @class . CompleteDeclaration ! = null )
return VisitClassDecl ( @class . CompleteDeclaration as Class ) ;
if ( ! VisitDeclarationContext ( @class ) )
return false ;
// Check for C++ operators that cannot be represented in C#.
CheckInvalidOperators ( @class ) ;
if ( Driver . Options . IsCSharpGenerator )
{
// 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 . Where ( o = > o . IsGenerated ) )
{
if ( ! IsValidOperatorOverload ( @operator ) )
{
Driver . Diagnostics . Debug ( DiagnosticId . InvalidOperatorOverload ,
"Invalid operator overload {0}::{1}" ,
@class . OriginalName , @operator . OperatorKind ) ;
@operator . ExplicitlyIgnore ( ) ;
continue ;
}
if ( @operator . SynthKind = = FunctionSynthKind . NonMemberOperator )
continue ;
if ( @operator . OperatorKind = = CXXOperatorKind . Subscript )
{
CreateIndexer ( @class , @operator ) ;
}
else
{
// 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 . LVReference
} ;
@operator . Parameters . Insert ( 0 , new Parameter
{
Name = Generator . GeneratedIdentifier ( "op" ) ,
QualifiedType = new QualifiedType ( type ) ,
Kind = ParameterKind . OperatorParameter
} ) ;
}
}
}
void CreateIndexer ( Class @class , Method @operator )
{
var property = new Property
{
Name = "Item" ,
QualifiedType = @operator . ReturnType ,
Access = @operator . Access ,
Namespace = @class ,
GetMethod = @operator
} ;
if ( ! @operator . ReturnType . Qualifiers . IsConst & & @operator . ReturnType . Type . IsAddress ( ) )
property . SetMethod = @operator ;
@ -114,148 +114,148 @@ namespace CppSharp.Passes
@@ -114,148 +114,148 @@ namespace CppSharp.Passes
}
property . Parameters . AddRange ( @operator . Parameters ) ;
@class . Properties . Add ( property ) ;
@operator . GenerationKind = GenerationKind . Internal ;
}
static void HandleMissingOperatorOverloadPair ( Class @class , CXXOperatorKind op1 ,
CXXOperatorKind op2 )
{
foreach ( var op in @class . Operators . Where (
o = > o . OperatorKind = = op1 | | o . OperatorKind = = op2 ) . ToList ( ) )
{
int index ;
var missingKind = CheckMissingOperatorOverloadPair ( @class , out index , op1 , op2 ,
op . Parameters . Last ( ) . Type ) ;
if ( missingKind = = CXXOperatorKind . None | | ! op . IsGenerated )
continue ;
var method = new Method ( )
{
Name = Operators . GetOperatorIdentifier ( missingKind ) ,
Namespace = @class ,
IsSynthetized = true ,
Kind = CXXMethodKind . Operator ,
OperatorKind = missingKind ,
ReturnType = op . ReturnType ,
Parameters = op . Parameters
} ;
@class . Methods . Insert ( index , method ) ;
}
}
static CXXOperatorKind CheckMissingOperatorOverloadPair ( Class @class ,
out int index , CXXOperatorKind op1 , CXXOperatorKind op2 , Type type )
{
var first = @class . Operators . FirstOrDefault ( o = > o . OperatorKind = = op1 & &
o . Parameters . Last ( ) . Type . Equals ( type ) ) ;
var second = @class . Operators . FirstOrDefault ( o = > o . OperatorKind = = op2 & &
o . Parameters . Last ( ) . Type . Equals ( type ) ) ;
var hasFirst = first ! = null ;
var hasSecond = second ! = null ;
if ( hasFirst & & ( ! hasSecond | | ! second . IsGenerated ) )
{
index = @class . Methods . IndexOf ( first ) ;
return op2 ;
}
if ( hasSecond & & ( ! hasFirst | | ! first . IsGenerated ) )
{
index = @class . Methods . IndexOf ( second ) ;
return op1 ;
}
index = 0 ;
return CXXOperatorKind . None ;
}
static bool IsValidOperatorOverload ( Method @operator )
{
// These follow the order described in MSDN (Overloadable Operators).
switch ( @operator . OperatorKind )
{
// These unary operators can be overloaded
case CXXOperatorKind . Plus :
case CXXOperatorKind . Minus :
case CXXOperatorKind . Exclaim :
case CXXOperatorKind . Tilde :
// These binary operators can be overloaded
case CXXOperatorKind . Slash :
case CXXOperatorKind . Percent :
case CXXOperatorKind . Amp :
case CXXOperatorKind . Pipe :
case CXXOperatorKind . Caret :
// The array indexing operator can be overloaded
case CXXOperatorKind . Subscript :
// The conversion operator can be overloaded
case CXXOperatorKind . Conversion :
return true ;
// The comparison operators can be overloaded if their return type is bool
case CXXOperatorKind . EqualEqual :
case CXXOperatorKind . ExclaimEqual :
case CXXOperatorKind . Less :
case CXXOperatorKind . Greater :
case CXXOperatorKind . LessEqual :
case CXXOperatorKind . GreaterEqual :
return @operator . ReturnType . Type . IsPrimitiveType ( PrimitiveType . Bool ) ;
// Only prefix operators can be overloaded
case CXXOperatorKind . PlusPlus :
case CXXOperatorKind . MinusMinus :
return @operator . Parameters . Count = = 0 ;
// Bitwise shift operators can only be overloaded if the second parameter is int
case CXXOperatorKind . LessLess :
case CXXOperatorKind . GreaterGreater :
PrimitiveType primitiveType ;
return @operator . Parameters . Last ( ) . Type . IsPrimitiveType ( out primitiveType ) & &
primitiveType = = PrimitiveType . Int32 ;
// No parameters means the dereference operator - cannot be overloaded
case CXXOperatorKind . Star :
return @operator . Parameters . Count > 0 ;
// 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 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 ;
}
}
}
}
@operator . GenerationKind = GenerationKind . Internal ;
}
static void HandleMissingOperatorOverloadPair ( Class @class , CXXOperatorKind op1 ,
CXXOperatorKind op2 )
{
foreach ( var op in @class . Operators . Where (
o = > o . OperatorKind = = op1 | | o . OperatorKind = = op2 ) . ToList ( ) )
{
int index ;
var missingKind = CheckMissingOperatorOverloadPair ( @class , out index , op1 , op2 ,
op . Parameters . Last ( ) . Type ) ;
if ( missingKind = = CXXOperatorKind . None | | ! op . IsGenerated )
continue ;
var method = new Method ( )
{
Name = Operators . GetOperatorIdentifier ( missingKind ) ,
Namespace = @class ,
IsSynthetized = true ,
Kind = CXXMethodKind . Operator ,
OperatorKind = missingKind ,
ReturnType = op . ReturnType ,
Parameters = op . Parameters
} ;
@class . Methods . Insert ( index , method ) ;
}
}
static CXXOperatorKind CheckMissingOperatorOverloadPair ( Class @class ,
out int index , CXXOperatorKind op1 , CXXOperatorKind op2 , Type type )
{
var first = @class . Operators . FirstOrDefault ( o = > o . OperatorKind = = op1 & &
o . Parameters . Last ( ) . Type . Equals ( type ) ) ;
var second = @class . Operators . FirstOrDefault ( o = > o . OperatorKind = = op2 & &
o . Parameters . Last ( ) . Type . Equals ( type ) ) ;
var hasFirst = first ! = null ;
var hasSecond = second ! = null ;
if ( hasFirst & & ( ! hasSecond | | ! second . IsGenerated ) )
{
index = @class . Methods . IndexOf ( first ) ;
return op2 ;
}
if ( hasSecond & & ( ! hasFirst | | ! first . IsGenerated ) )
{
index = @class . Methods . IndexOf ( second ) ;
return op1 ;
}
index = 0 ;
return CXXOperatorKind . None ;
}
static bool IsValidOperatorOverload ( Method @operator )
{
// These follow the order described in MSDN (Overloadable Operators).
switch ( @operator . OperatorKind )
{
// These unary operators can be overloaded
case CXXOperatorKind . Plus :
case CXXOperatorKind . Minus :
case CXXOperatorKind . Exclaim :
case CXXOperatorKind . Tilde :
// These binary operators can be overloaded
case CXXOperatorKind . Slash :
case CXXOperatorKind . Percent :
case CXXOperatorKind . Amp :
case CXXOperatorKind . Pipe :
case CXXOperatorKind . Caret :
// The array indexing operator can be overloaded
case CXXOperatorKind . Subscript :
// The conversion operator can be overloaded
case CXXOperatorKind . Conversion :
return true ;
// The comparison operators can be overloaded if their return type is bool
case CXXOperatorKind . EqualEqual :
case CXXOperatorKind . ExclaimEqual :
case CXXOperatorKind . Less :
case CXXOperatorKind . Greater :
case CXXOperatorKind . LessEqual :
case CXXOperatorKind . GreaterEqual :
return @operator . ReturnType . Type . IsPrimitiveType ( PrimitiveType . Bool ) ;
// Only prefix operators can be overloaded
case CXXOperatorKind . PlusPlus :
case CXXOperatorKind . MinusMinus :
return @operator . Parameters . Count = = 0 ;
// Bitwise shift operators can only be overloaded if the second parameter is int
case CXXOperatorKind . LessLess :
case CXXOperatorKind . GreaterGreater :
PrimitiveType primitiveType ;
return @operator . Parameters . Last ( ) . Type . IsPrimitiveType ( out primitiveType ) & &
primitiveType = = PrimitiveType . Int32 ;
// No parameters means the dereference operator - cannot be overloaded
case CXXOperatorKind . Star :
return @operator . Parameters . Count > 0 ;
// 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 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 ;
}
}
}
}