-
Notifications
You must be signed in to change notification settings - Fork 526
/
Copy pathValidateOperatorsPass.cs
147 lines (131 loc) · 6.14 KB
/
ValidateOperatorsPass.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
using System.Linq;
using CppSharp.AST;
using CppSharp.AST.Extensions;
using CppSharp.Generators;
namespace CppSharp.Passes
{
/// <summary>
/// Validates operators for C# (if they can be overloaded).
/// </summary>
public class ValidateOperatorsPass : TranslationUnitPass
{
public ValidateOperatorsPass() => VisitOptions.ResetFlags(
VisitFlags.ClassMethods | VisitFlags.ClassProperties |
VisitFlags.ClassTemplateSpecializations);
public override bool VisitMethodDecl(Method method)
{
if (!base.VisitMethodDecl(method) ||
!method.IsOperator || !method.IsGenerated)
return false;
if (!IsValidOperatorOverload(method) || method.IsPure)
{
Diagnostics.Debug("Invalid operator overload {0}::{1}",
method.Namespace.Name, method.OperatorKind);
method.ExplicitlyIgnore();
}
return true;
}
private 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 operators can be overloaded
case CXXOperatorKind.Conversion:
case CXXOperatorKind.ExplicitConversion:
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:
Class @class;
var returnType = @operator.OriginalReturnType.Type.Desugar();
returnType = (returnType.GetFinalPointee() ?? returnType).Desugar();
return returnType.TryGetClass(out @class) &&
@class.GetNonIgnoredRootBase() ==
((Class)@operator.Namespace).GetNonIgnoredRootBase() &&
@operator.Parameters.Count == 0;
// Bitwise shift operators can only be overloaded if the second parameter is int
case CXXOperatorKind.LessLess:
case CXXOperatorKind.GreaterGreater:
{
Parameter parameter = @operator.Parameters.Last();
Type type = parameter.Type.Desugar();
switch (Options.GeneratorKind)
{
case GeneratorKind.CLI:
return type.IsPrimitiveType(PrimitiveType.Int);
case GeneratorKind.CSharp:
Types.TypeMap typeMap;
if (Context.TypeMaps.FindTypeMap(type, out typeMap))
{
var mappedTo = typeMap.CSharpSignatureType(
new TypePrinterContext
{
Parameter = parameter,
Type = type,
Method = @operator,
});
var cilType = mappedTo as CILType;
if (cilType?.Type == typeof(int))
return true;
}
break;
}
return false;
}
// 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.Coawait:
case CXXOperatorKind.New:
case CXXOperatorKind.Delete:
case CXXOperatorKind.Array_New:
case CXXOperatorKind.Array_Delete:
default:
return false;
}
}
}
}