Browse Source

Don't check the unsupported operator= for symbols

Signed-off-by: Dimitar Dobrev <dpldobrev@protonmail.com>
pull/1517/head
Dimitar Dobrev 5 years ago
parent
commit
6f276debf6
  1. 16
      src/Generator.Tests/Passes/TestPasses.cs
  2. 11
      src/Generator/Driver.cs
  3. 8
      src/Generator/Passes/CheckDuplicatedNamesPass.cs
  4. 144
      src/Generator/Passes/CheckOperatorsOverloads.cs
  5. 156
      src/Generator/Passes/ValidateOperatorsPass.cs

16
src/Generator.Tests/Passes/TestPasses.cs

@ -186,21 +186,17 @@ namespace CppSharp.Generator.Tests.Passes @@ -186,21 +186,17 @@ namespace CppSharp.Generator.Tests.Passes
Assert.IsNotNull(@class);
var overloads = @class.Methods.Where(m => m.Name == "Method");
var constMethod = overloads
.Where(m => m.IsConst && m.Parameters.Count == 0)
.FirstOrDefault();
.FirstOrDefault(m => m.IsConst && m.Parameters.Count == 0);
var nonConstMethod = overloads
.Where(m => !m.IsConst && m.Parameters.Count == 0)
.FirstOrDefault();
.FirstOrDefault(m => !m.IsConst && m.Parameters.Count == 0);
Assert.IsNotNull(constMethod);
Assert.IsNotNull(nonConstMethod);
Assert.IsTrue(constMethod.GenerationKind == GenerationKind.None);
Assert.IsTrue(nonConstMethod.GenerationKind == GenerationKind.Generate);
var constMethodWithParam = overloads
.Where(m => m.IsConst && m.Parameters.Count == 1)
.FirstOrDefault();
.FirstOrDefault(m => m.IsConst && m.Parameters.Count == 1);
var nonConstMethodWithParam = overloads
.Where(m => !m.IsConst && m.Parameters.Count == 1)
.FirstOrDefault();
.FirstOrDefault(m => !m.IsConst && m.Parameters.Count == 1);
Assert.IsNotNull(constMethodWithParam);
Assert.IsNotNull(nonConstMethodWithParam);
Assert.IsTrue(constMethodWithParam.GenerationKind == GenerationKind.None);
@ -226,7 +222,7 @@ namespace CppSharp.Generator.Tests.Passes @@ -226,7 +222,7 @@ namespace CppSharp.Generator.Tests.Passes
[Test]
public void TestAbstractOperator()
{
passBuilder.AddPass(new CheckOperatorsOverloadsPass());
passBuilder.AddPass(new ValidateOperatorsPass());
passBuilder.RunPasses(pass => pass.VisitASTContext(AstContext));
var @class = AstContext.FindDecl<Class>("ClassWithAbstractOperator").First();
@ -246,7 +242,7 @@ namespace CppSharp.Generator.Tests.Passes @@ -246,7 +242,7 @@ namespace CppSharp.Generator.Tests.Passes
Assert.IsNotNull(@public);
Assert.AreEqual(AccessSpecifier.Public, @public.Access); */
var @protected = @class.Fields.Where(f => f.Name == "Protected").FirstOrDefault();
var @protected = @class.Fields.Find(f => f.Name == "Protected");
Assert.IsNotNull(@protected);
Assert.AreEqual(AccessSpecifier.Protected, @protected.Access);
}

11
src/Generator/Driver.cs

@ -223,17 +223,18 @@ namespace CppSharp @@ -223,17 +223,18 @@ namespace CppSharp
TranslationUnitPasses.AddPass(new CheckIgnoredDeclsPass());
}
if (Options.IsCLIGenerator || Options.IsCSharpGenerator)
{
TranslationUnitPasses.AddPass(new MoveFunctionToClassPass());
TranslationUnitPasses.AddPass(new ValidateOperatorsPass());
}
library.SetupPasses(this);
TranslationUnitPasses.AddPass(new FindSymbolsPass());
TranslationUnitPasses.AddPass(new CheckMacroPass());
TranslationUnitPasses.AddPass(new CheckStaticClass());
if (Options.IsCLIGenerator || Options.IsCSharpGenerator)
{
TranslationUnitPasses.AddPass(new MoveFunctionToClassPass());
}
TranslationUnitPasses.AddPass(new CheckAmbiguousFunctions());
TranslationUnitPasses.AddPass(new ConstructorToConversionOperatorPass());
TranslationUnitPasses.AddPass(new MarshalPrimitivePointersAsRefTypePass());

8
src/Generator/Passes/CheckDuplicatedNamesPass.cs

@ -189,13 +189,7 @@ namespace CppSharp.Passes @@ -189,13 +189,7 @@ namespace CppSharp.Passes
public class CheckDuplicatedNamesPass : TranslationUnitPass
{
private readonly IDictionary<string, DeclarationName> names;
public CheckDuplicatedNamesPass()
{
ClearVisitedDeclarations = false;
names = new Dictionary<string, DeclarationName>();
}
private readonly IDictionary<string, DeclarationName> names = new Dictionary<string, DeclarationName>();
public override bool VisitASTContext(ASTContext context)
{

144
src/Generator/Passes/CheckOperatorsOverloads.cs

@ -10,17 +10,24 @@ namespace CppSharp.Passes @@ -10,17 +10,24 @@ namespace CppSharp.Passes
/// </summary>
public class CheckOperatorsOverloadsPass : TranslationUnitPass
{
public CheckOperatorsOverloadsPass()
{
ClearVisitedDeclarations = false;
}
public CheckOperatorsOverloadsPass() =>
VisitOptions.VisitClassBases =
VisitOptions.VisitClassFields =
VisitOptions.VisitEventParameters =
VisitOptions.VisitFunctionParameters =
VisitOptions.VisitFunctionReturnType =
VisitOptions.VisitClassMethods =
VisitOptions.VisitNamespaceEnums =
VisitOptions.VisitNamespaceEvents =
VisitOptions.VisitNamespaceTemplates =
VisitOptions.VisitNamespaceTypedefs =
VisitOptions.VisitNamespaceVariables =
VisitOptions.VisitPropertyAccessors =
VisitOptions.VisitTemplateArguments = false;
public override bool VisitClassDecl(Class @class)
{
if (@class.CompleteDeclaration != null)
return VisitClassDecl(@class.CompleteDeclaration as Class);
if (!VisitDeclarationContext(@class))
if (!base.VisitClassDecl(@class))
return false;
// Check for C++ operators that cannot be represented in .NET.
@ -49,14 +56,6 @@ namespace CppSharp.Passes @@ -49,14 +56,6 @@ namespace CppSharp.Passes
{
foreach (var @operator in @class.Operators.Where(o => o.IsGenerated))
{
if (!IsValidOperatorOverload(@operator) || @operator.IsPure)
{
Diagnostics.Debug("Invalid operator overload {0}::{1}",
@class.OriginalName, @operator.OperatorKind);
@operator.ExplicitlyIgnore();
continue;
}
if (@operator.IsNonMemberOperator)
continue;
@ -184,118 +183,5 @@ namespace CppSharp.Passes @@ -184,118 +183,5 @@ namespace CppSharp.Passes
index = 0;
return CXXOperatorKind.None;
}
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
});
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;
}
}
}
}

156
src/Generator/Passes/ValidateOperatorsPass.cs

@ -0,0 +1,156 @@ @@ -0,0 +1,156 @@
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.VisitClassBases =
VisitOptions.VisitClassFields =
VisitOptions.VisitEventParameters =
VisitOptions.VisitFunctionParameters =
VisitOptions.VisitFunctionReturnType =
VisitOptions.VisitNamespaceEnums =
VisitOptions.VisitNamespaceEvents =
VisitOptions.VisitNamespaceTemplates =
VisitOptions.VisitNamespaceTypedefs =
VisitOptions.VisitNamespaceVariables =
VisitOptions.VisitPropertyAccessors =
VisitOptions.VisitTemplateArguments = false;
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
});
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;
}
}
}
}
Loading…
Cancel
Save