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.
189 lines
6.4 KiB
189 lines
6.4 KiB
using System; |
|
using System.Linq; |
|
using CppSharp.AST; |
|
using CppSharp.AST.Extensions; |
|
|
|
namespace CppSharp.Passes |
|
{ |
|
/// <summary> |
|
/// Checks for ambiguous functions/method declarations. |
|
/// |
|
/// Example: |
|
/// struct S |
|
/// { |
|
/// void Foo(int a, int b = 0); |
|
/// void Foo(int a); |
|
/// void Bar(); |
|
/// void Bar() const; |
|
/// |
|
/// void Qux(int& i); |
|
/// void Qux(int&& i); |
|
/// void Qux(const int& i); |
|
/// }; |
|
/// |
|
/// When we call Foo(0) the compiler will not know which call we want and |
|
/// will error out so we need to detect this and either ignore the methods |
|
/// or flag them such that the generator can explicitly disambiguate when |
|
/// generating the call to the native code. |
|
/// </summary> |
|
public class CheckAmbiguousFunctions : TranslationUnitPass |
|
{ |
|
public override bool VisitFunctionDecl(AST.Function function) |
|
{ |
|
if (!VisitDeclaration(function)) |
|
return false; |
|
|
|
if (function.IsAmbiguous) |
|
return false; |
|
|
|
var overloads = function.Namespace.GetOverloads(function); |
|
|
|
foreach (var overload in overloads) |
|
{ |
|
if (function.OperatorKind == CXXOperatorKind.Conversion) |
|
continue; |
|
if (function.OperatorKind == CXXOperatorKind.ExplicitConversion) |
|
continue; |
|
|
|
if (overload == function) continue; |
|
|
|
if (!overload.IsGenerated) continue; |
|
|
|
if (CheckConstnessForAmbiguity(function, overload) || |
|
CheckDefaultParametersForAmbiguity(function, overload) || |
|
CheckSingleParameterPointerConstnessForAmbiguity(function, overload)) |
|
{ |
|
function.IsAmbiguous = true; |
|
overload.IsAmbiguous = true; |
|
} |
|
} |
|
|
|
if (function.IsAmbiguous) |
|
Diagnostics.Debug("Found ambiguous overload: {0}", |
|
function.QualifiedOriginalName); |
|
|
|
return true; |
|
} |
|
|
|
private static bool CheckDefaultParametersForAmbiguity(Function function, Function overload) |
|
{ |
|
var commonParameters = Math.Min(function.Parameters.Count, overload.Parameters.Count); |
|
|
|
var i = 0; |
|
for (; i < commonParameters; ++i) |
|
{ |
|
var funcParam = function.Parameters[i]; |
|
var overloadParam = overload.Parameters[i]; |
|
|
|
if (!funcParam.QualifiedType.Equals(overloadParam.QualifiedType)) |
|
return false; |
|
} |
|
|
|
for (; i < function.Parameters.Count; ++i) |
|
{ |
|
var funcParam = function.Parameters[i]; |
|
if (!funcParam.HasDefaultValue) |
|
return false; |
|
} |
|
|
|
for (; i < overload.Parameters.Count; ++i) |
|
{ |
|
var overloadParam = overload.Parameters[i]; |
|
if (!overloadParam.HasDefaultValue) |
|
return false; |
|
} |
|
|
|
if (function.Parameters.Count > overload.Parameters.Count) |
|
overload.ExplicitlyIgnore(); |
|
else |
|
function.ExplicitlyIgnore(); |
|
|
|
return true; |
|
} |
|
|
|
private static bool CheckConstnessForAmbiguity(Function function, Function overload) |
|
{ |
|
var method1 = function as Method; |
|
var method2 = overload as Method; |
|
if (method1 == null || method2 == null) |
|
return false; |
|
|
|
var sameParams = method1.Parameters.SequenceEqual(method2.Parameters, |
|
ParameterTypeComparer.Instance); |
|
|
|
if (method1.IsConst && !method2.IsConst && sameParams) |
|
{ |
|
method1.ExplicitlyIgnore(); |
|
return true; |
|
} |
|
|
|
if (method2.IsConst && !method1.IsConst && sameParams) |
|
{ |
|
method2.ExplicitlyIgnore(); |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
private static bool CheckSingleParameterPointerConstnessForAmbiguity( |
|
Function function, Function overload) |
|
{ |
|
var functionParams = function.Parameters.Where( |
|
p => p.Kind == ParameterKind.Regular).ToList(); |
|
// It's difficult to handle this case for more than one parameter |
|
// For example, if we have: |
|
// void f(float&, const int&); |
|
// void f(const float&, int&); |
|
// what should we do? Generate both? Generate the first one encountered? |
|
// Generate the one with the least amount of "complex" parameters? |
|
// So let's just start with the simplest case for the time being |
|
if (functionParams.Count != 1) |
|
return false; |
|
var overloadParams = overload.Parameters.Where( |
|
p => p.Kind == ParameterKind.Regular).ToList(); |
|
if (overloadParams.Count != 1) |
|
return false; |
|
|
|
var parameterFunction = functionParams[0]; |
|
var parameterOverload = overloadParams[0]; |
|
|
|
var pointerParamFunction = parameterFunction.Type.Desugar() as PointerType; |
|
var pointerParamOverload = parameterOverload.Type.Desugar() as PointerType; |
|
|
|
if (pointerParamFunction == null || pointerParamOverload == null) |
|
return false; |
|
|
|
if (!pointerParamFunction.GetPointee().Equals(pointerParamOverload.GetPointee())) |
|
return false; |
|
|
|
if (parameterFunction.IsConst && !parameterOverload.IsConst) |
|
{ |
|
function.ExplicitlyIgnore(); |
|
return true; |
|
} |
|
|
|
if (parameterOverload.IsConst && !parameterFunction.IsConst) |
|
{ |
|
overload.ExplicitlyIgnore(); |
|
return true; |
|
} |
|
|
|
if (pointerParamFunction.Modifier == PointerType.TypeModifier.RVReference && |
|
pointerParamOverload.Modifier != PointerType.TypeModifier.RVReference) |
|
{ |
|
function.ExplicitlyIgnore(); |
|
return true; |
|
} |
|
|
|
if (pointerParamFunction.Modifier != PointerType.TypeModifier.RVReference && |
|
pointerParamOverload.Modifier == PointerType.TypeModifier.RVReference) |
|
{ |
|
overload.ExplicitlyIgnore(); |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
} |
|
}
|
|
|