From 7125109e3f474a829a85a85ecfb78c983b09b476 Mon Sep 17 00:00:00 2001 From: marcos henrich Date: Wed, 16 Apr 2014 19:14:57 +0100 Subject: [PATCH] Deprecated ExplicityIgnored use ExplicitlyIgnore(). Getting ExplicityIgnored and setting ExplicityIgnored to false don't make much sense anymore. Conflicts: src/Generator/Passes/CheckOperatorsOverloads.cs --- src/AST/Declaration.cs | 20 +- src/CppParser/Bindings/ParserGen.cs | 4 +- src/Generator.Tests/Passes/TestPasses.cs | 8 +- src/Generator/Library.cs | 14 +- .../Passes/CheckAmbiguousFunctions.cs | 8 +- .../Passes/CheckDuplicatedNamesPass.cs | 4 +- src/Generator/Passes/CheckIgnoredDecls.cs | 38 +- src/Generator/Passes/CheckMacrosPass.cs | 12 +- .../Passes/CheckOperatorsOverloads.cs | 484 +++++++++--------- .../Passes/CleanInvalidDeclNamesPass.cs | 6 +- src/Generator/Passes/FindSymbolsPass.cs | 2 +- .../Passes/FunctionToInstanceMethodPass.cs | 2 +- .../Passes/FunctionToStaticMethodPass.cs | 2 +- .../Passes/MoveFunctionToClassPass.cs | 4 +- .../Passes/MoveOperatorToClassPass.cs | 2 +- 15 files changed, 309 insertions(+), 301 deletions(-) diff --git a/src/AST/Declaration.cs b/src/AST/Declaration.cs index 92fa06b5..eb94daca 100644 --- a/src/AST/Declaration.cs +++ b/src/AST/Declaration.cs @@ -192,9 +192,6 @@ namespace CppSharp.AST { get { - if(ExplicityIgnored) - return GenerationKind.None; - if (generationKind.HasValue) return generationKind.Value; @@ -244,13 +241,24 @@ namespace CppSharp.AST } } - public bool ExplicityIgnored { get; set; } + public void ExplicitlyIgnore() + { + GenerationKind = GenerationKind.None; + } + + + [Obsolete("Replace set by ExplicitlyIgnore(). Replace get by GenerationKind == GenerationKind.None.")] + public bool ExplicityIgnored + { + get { return GenerationKind == GenerationKind.None; } + set { if (value) ExplicitlyIgnore(); } + } - [Obsolete("Replace set by ExplicityIgnored. Replace get by IsGenerated, IsInternal or IsDeclared.")] + [Obsolete("Replace set by ExplicitlyIgnore(). Replace get by GenerationKind == GenerationKind.None.")] public virtual bool Ignore { get { return GenerationKind == GenerationKind.None; } - set { ExplicityIgnored = value; } + set { if (value) ExplicitlyIgnore(); } } public AccessSpecifier Access { get; set; } diff --git a/src/CppParser/Bindings/ParserGen.cs b/src/CppParser/Bindings/ParserGen.cs index e84bdc4c..ed1b9f44 100644 --- a/src/CppParser/Bindings/ParserGen.cs +++ b/src/CppParser/Bindings/ParserGen.cs @@ -150,7 +150,7 @@ namespace CppSharp if (!IsStdType(field.QualifiedType)) return false; - field.ExplicityIgnored = true; + field.ExplicitlyIgnore(); return true; } @@ -161,7 +161,7 @@ namespace CppSharp if (function.Parameters.Any(param => IsStdType(param.QualifiedType))) { - function.ExplicityIgnored = true; + function.ExplicitlyIgnore(); return false; } diff --git a/src/Generator.Tests/Passes/TestPasses.cs b/src/Generator.Tests/Passes/TestPasses.cs index 2c0b73ce..c2656f73 100644 --- a/src/Generator.Tests/Passes/TestPasses.cs +++ b/src/Generator.Tests/Passes/TestPasses.cs @@ -55,13 +55,13 @@ namespace CppSharp.Generator.Tests.Passes { var c = AstContext.Class("Foo"); - Assert.IsFalse(AstContext.Function("FooStart").ExplicityIgnored); + Assert.IsTrue(AstContext.Function("FooStart").IsGenerated); Assert.IsNull(c.Method("Start")); passBuilder.AddPass(new FunctionToStaticMethodPass()); passBuilder.RunPasses(pass => pass.VisitLibrary(AstContext)); - Assert.IsTrue(AstContext.Function("FooStart").ExplicityIgnored); + Assert.IsFalse(AstContext.Function("FooStart").IsGenerated); Assert.IsNotNull(c.Method("Start")); } @@ -105,8 +105,8 @@ namespace CppSharp.Generator.Tests.Passes public void TestIgnoringMethod() { AstContext.IgnoreClassMethodWithName("Foo", "toIgnore"); - Assert.IsTrue(AstContext.FindClass("Foo").First().Methods.Find( - m => m.Name == "toIgnore").ExplicityIgnored); + Assert.IsFalse(AstContext.FindClass("Foo").First().Methods.Find( + m => m.Name == "toIgnore").IsGenerated); } } } diff --git a/src/Generator/Library.cs b/src/Generator/Library.cs index d72002ae..5a8aba08 100644 --- a/src/Generator/Library.cs +++ b/src/Generator/Library.cs @@ -54,7 +54,7 @@ namespace CppSharp { Enumeration @enum = context.GetEnumWithMatchingItem(pattern); if (@enum != null) - @enum.ExplicityIgnored = true; + @enum.ExplicitlyIgnore(); } public static void SetNameOfEnumWithMatchingItem(this ASTContext context, string pattern, @@ -184,7 +184,7 @@ namespace CppSharp public static void IgnoreClassWithName(this ASTContext context, string name) { foreach (var @class in context.FindClass(name)) - @class.ExplicityIgnored = true; + @class.ExplicitlyIgnore(); } public static void SetClassAsOpaque(this ASTContext context, string name) @@ -270,7 +270,7 @@ namespace CppSharp public static void IgnoreFunctionWithName(this ASTContext context, string name) { foreach (var function in context.FindFunction(name)) - function.ExplicityIgnored = true; + function.ExplicitlyIgnore(); } public static void IgnoreFunctionWithPattern(this ASTContext context, string pattern) @@ -280,7 +280,7 @@ namespace CppSharp foreach (var function in unit.Functions) { if (Regex.Match(function.Name, pattern).Success) - function.ExplicityIgnored = true; + function.ExplicitlyIgnore(); } } } @@ -299,7 +299,7 @@ namespace CppSharp where method.Name == name select method) { - method.ExplicityIgnored = true; + method.ExplicitlyIgnore(); } } @@ -308,7 +308,7 @@ namespace CppSharp foreach (var @class in context.FindClass(name)) { foreach (var classField in @class.Fields.FindAll(f => f.Name == field)) - classField.ExplicityIgnored = true; + classField.ExplicitlyIgnore(); } } @@ -334,7 +334,7 @@ namespace CppSharp foreach (var unit in units) { - unit.ExplicityIgnored = true; + unit.ExplicitlyIgnore(); } } diff --git a/src/Generator/Passes/CheckAmbiguousFunctions.cs b/src/Generator/Passes/CheckAmbiguousFunctions.cs index 49c1e07b..922dcc3a 100644 --- a/src/Generator/Passes/CheckAmbiguousFunctions.cs +++ b/src/Generator/Passes/CheckAmbiguousFunctions.cs @@ -88,9 +88,9 @@ namespace CppSharp.Passes } if (function.Parameters.Count > overload.Parameters.Count) - overload.ExplicityIgnored = true; + overload.ExplicitlyIgnore(); else - function.ExplicityIgnored = true; + function.ExplicitlyIgnore(); return true; } @@ -104,13 +104,13 @@ namespace CppSharp.Passes if (method1.IsConst && !method2.IsConst) { - method1.ExplicityIgnored = true; + method1.ExplicitlyIgnore(); return false; } if (method2.IsConst && !method1.IsConst) { - method2.ExplicityIgnored = true; + method2.ExplicitlyIgnore(); return false; } } diff --git a/src/Generator/Passes/CheckDuplicatedNamesPass.cs b/src/Generator/Passes/CheckDuplicatedNamesPass.cs index df64939f..9683fb82 100644 --- a/src/Generator/Passes/CheckDuplicatedNamesPass.cs +++ b/src/Generator/Passes/CheckDuplicatedNamesPass.cs @@ -72,12 +72,12 @@ namespace CppSharp.Passes { // TODO: turn into a method; append the original type (say, "signed long") of the last parameter to the type so that the user knows which overload is called Driver.Diagnostics.EmitWarning("Duplicate operator {0} ignored", function.Name); - function.ExplicityIgnored = true; + function.ExplicitlyIgnore(); } else if (method != null && method.IsConstructor) { Driver.Diagnostics.EmitWarning("Duplicate constructor {0} ignored", function.Name); - function.ExplicityIgnored = true; + function.ExplicitlyIgnore(); } else function.Name += methodCount.ToString(CultureInfo.InvariantCulture); diff --git a/src/Generator/Passes/CheckIgnoredDecls.cs b/src/Generator/Passes/CheckIgnoredDecls.cs index 4a1b0274..e851524a 100644 --- a/src/Generator/Passes/CheckIgnoredDecls.cs +++ b/src/Generator/Passes/CheckIgnoredDecls.cs @@ -33,20 +33,20 @@ namespace CppSharp.Passes if (AlreadyVisited(decl)) return false; - if (decl.ExplicityIgnored) + if (decl.GenerationKind == GenerationKind.None) return true; if (!CheckDeclarationAccess(decl)) { Log.Debug("Decl '{0}' was ignored due to invalid access", decl.Name); - decl.ExplicityIgnored = true; + decl.ExplicitlyIgnore(); return true; } if (decl.IsDependent) { - decl.ExplicityIgnored = true; + decl.ExplicitlyIgnore(); Log.Debug("Decl '{0}' was ignored due to dependent context", decl.Name); return true; @@ -66,7 +66,7 @@ namespace CppSharp.Passes if (!HasInvalidType(type, out msg)) return false; - field.ExplicityIgnored = true; + field.ExplicitlyIgnore(); var @class = (Class)field.Namespace; @@ -89,7 +89,7 @@ namespace CppSharp.Passes string msg; if (HasInvalidType(ret.Type, out msg)) { - function.ExplicityIgnored = true; + function.ExplicitlyIgnore(); Log.Debug("Function '{0}' was ignored due to {1} return decl", function.Name, msg); return false; @@ -99,7 +99,7 @@ namespace CppSharp.Passes { if (HasInvalidDecl(param, out msg)) { - function.ExplicityIgnored = true; + function.ExplicitlyIgnore(); Log.Debug("Function '{0}' was ignored due to {1} param", function.Name, msg); return false; @@ -107,7 +107,7 @@ namespace CppSharp.Passes if (HasInvalidType(param.Type, out msg)) { - function.ExplicityIgnored = true; + function.ExplicitlyIgnore(); Log.Debug("Function '{0}' was ignored due to {1} param", function.Name, msg); return false; @@ -116,7 +116,7 @@ namespace CppSharp.Passes var decayedType = param.Type.Desugar() as DecayedType; if (decayedType != null) { - function.ExplicityIgnored = true; + function.ExplicitlyIgnore(); Log.Debug("Function '{0}' was ignored due to unsupported decayed type param", function.Name); return false; @@ -128,7 +128,7 @@ namespace CppSharp.Passes param.Type.Desugar().IsTagDecl(out retClass); if (retClass == null) { - function.ExplicityIgnored = true; + function.ExplicitlyIgnore(); Log.Debug( "Function '{0}' was ignored due to an indirect return param not of a tag type", function.Name); @@ -161,7 +161,7 @@ namespace CppSharp.Passes "Virtual method '{0}' was ignored due to ignored base '{1}'", method.QualifiedOriginalName, ignoredBase.Name); - method.ExplicityIgnored = true; + method.ExplicitlyIgnore(); return false; } @@ -174,7 +174,7 @@ namespace CppSharp.Passes "Virtual method '{0}' was ignored due to ignored override '{1}'", method.QualifiedOriginalName, baseOverride.Name); - method.ExplicityIgnored = true; + method.ExplicitlyIgnore(); return false; } } @@ -217,7 +217,7 @@ namespace CppSharp.Passes string msg; if (HasInvalidType(typedef.Type, out msg)) { - typedef.ExplicityIgnored = true; + typedef.ExplicitlyIgnore(); Log.Debug("Typedef '{0}' was ignored due to {1} type", typedef.Name, msg); return false; @@ -234,7 +234,7 @@ namespace CppSharp.Passes string msg; if (HasInvalidDecl(property, out msg)) { - property.ExplicityIgnored = true; + property.ExplicitlyIgnore(); Log.Debug("Property '{0}' was ignored due to {1} decl", property.Name, msg); return false; @@ -242,7 +242,7 @@ namespace CppSharp.Passes if (HasInvalidType(property.Type, out msg)) { - property.ExplicityIgnored = true; + property.ExplicitlyIgnore(); Log.Debug("Property '{0}' was ignored due to {1} type", property.Name, msg); return false; @@ -259,7 +259,7 @@ namespace CppSharp.Passes string msg; if (HasInvalidDecl(variable, out msg)) { - variable.ExplicityIgnored = true; + variable.ExplicitlyIgnore(); Log.Debug("Variable '{0}' was ignored due to {1} decl", variable.Name, msg); return false; @@ -267,7 +267,7 @@ namespace CppSharp.Passes if (HasInvalidType(variable.Type, out msg)) { - variable.ExplicityIgnored = true; + variable.ExplicitlyIgnore(); Log.Debug("Variable '{0}' was ignored due to {1} type", variable.Name, msg); return false; @@ -284,7 +284,7 @@ namespace CppSharp.Passes string msg; if (HasInvalidDecl(@event, out msg)) { - @event.ExplicityIgnored = true; + @event.ExplicitlyIgnore(); Log.Debug("Event '{0}' was ignored due to {1} decl", @event.Name, msg); return false; @@ -294,7 +294,7 @@ namespace CppSharp.Passes { if (HasInvalidDecl(param, out msg)) { - @event.ExplicityIgnored = true; + @event.ExplicitlyIgnore(); Log.Debug("Event '{0}' was ignored due to {1} param", @event.Name, msg); return false; @@ -302,7 +302,7 @@ namespace CppSharp.Passes if (HasInvalidType(param.Type, out msg)) { - @event.ExplicityIgnored = true; + @event.ExplicitlyIgnore(); Log.Debug("Event '{0}' was ignored due to {1} param", @event.Name, msg); return false; diff --git a/src/Generator/Passes/CheckMacrosPass.cs b/src/Generator/Passes/CheckMacrosPass.cs index 2d78dede..3a63cb6f 100644 --- a/src/Generator/Passes/CheckMacrosPass.cs +++ b/src/Generator/Passes/CheckMacrosPass.cs @@ -1,5 +1,5 @@ -using System; -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using CppSharp.AST; @@ -74,7 +74,7 @@ namespace CppSharp.Passes e.Location != MacroLocation.ClassBody && e.Location != MacroLocation.FunctionBody && e.Location != MacroLocation.FunctionParameters)) - decl.ExplicityIgnored = true; + decl.ExplicitlyIgnore(); if (expansions.Any(e => e.Text == Prefix + "_IGNORE_GEN" && e.Location != MacroLocation.ClassBody && @@ -89,7 +89,7 @@ namespace CppSharp.Passes if (expansions.Any(e => e.Text == Prefix + "_IGNORE_FILE")) { - unit.ExplicityIgnored = true; + unit.ExplicitlyIgnore(); } return base.VisitTranslationUnit(unit); @@ -149,7 +149,7 @@ namespace CppSharp.Passes if (expansions.Any(e => e.Text == Prefix + "_HASHCODE" || e.Text == Prefix + "_EQUALS")) - method.ExplicityIgnored = true; + method.ExplicitlyIgnore(); return base.VisitMethodDecl(method); } @@ -184,7 +184,7 @@ namespace CppSharp.Passes var setMethod = property.SetMethod; if (setMethod != null) - property.SetMethod.ExplicityIgnored = true; + property.SetMethod.ExplicitlyIgnore(); } return base.VisitProperty(property); diff --git a/src/Generator/Passes/CheckOperatorsOverloads.cs b/src/Generator/Passes/CheckOperatorsOverloads.cs index 9b2cca86..31cef683 100644 --- a/src/Generator/Passes/CheckOperatorsOverloads.cs +++ b/src/Generator/Passes/CheckOperatorsOverloads.cs @@ -1,102 +1,102 @@ -using System.Linq; -using CppSharp.AST; -using CppSharp.AST.Extensions; -using CppSharp.Generators; - -namespace CppSharp.Passes -{ - /// - /// Checks for missing operator overloads required by C#. - /// - 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 +{ + /// + /// Checks for missing operator overloads required by C#. + /// + 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 } 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; + } + } + } +} diff --git a/src/Generator/Passes/CleanInvalidDeclNamesPass.cs b/src/Generator/Passes/CleanInvalidDeclNamesPass.cs index d2cba96b..8e1be9e0 100644 --- a/src/Generator/Passes/CleanInvalidDeclNamesPass.cs +++ b/src/Generator/Passes/CleanInvalidDeclNamesPass.cs @@ -36,7 +36,7 @@ namespace CppSharp.Passes if (decl is Class && string.IsNullOrWhiteSpace(decl.Name)) { decl.Name = "_"; - decl.ExplicityIgnored = true; + decl.ExplicitlyIgnore(); return false; } @@ -107,10 +107,10 @@ namespace CppSharp.Passes // so we ignore the class and process just the typedef. if (@class != null) - typedef.ExplicityIgnored = true; + typedef.ExplicitlyIgnore(); if (typedef.Type == null) - typedef.ExplicityIgnored = true; + typedef.ExplicitlyIgnore(); return base.VisitTypedefDecl(typedef); } diff --git a/src/Generator/Passes/FindSymbolsPass.cs b/src/Generator/Passes/FindSymbolsPass.cs index 511b58f9..cf4ed6a6 100644 --- a/src/Generator/Passes/FindSymbolsPass.cs +++ b/src/Generator/Passes/FindSymbolsPass.cs @@ -15,7 +15,7 @@ namespace CppSharp.Passes if (mangledDecl != null && !(method != null && (method.IsPure || method.IsSynthetized)) && !VisitMangledDeclaration(mangledDecl)) { - decl.ExplicityIgnored = true; + decl.ExplicitlyIgnore(); return false; } diff --git a/src/Generator/Passes/FunctionToInstanceMethodPass.cs b/src/Generator/Passes/FunctionToInstanceMethodPass.cs index c5cc7bd9..88973faa 100644 --- a/src/Generator/Passes/FunctionToInstanceMethodPass.cs +++ b/src/Generator/Passes/FunctionToInstanceMethodPass.cs @@ -39,7 +39,7 @@ namespace CppSharp.Passes return false; function.Name = function.Name.Substring(@class.Name.Length); - function.ExplicityIgnored = true; + function.ExplicitlyIgnore(); // Create a new fake method so it acts as an instance method. var method = new Method diff --git a/src/Generator/Passes/FunctionToStaticMethodPass.cs b/src/Generator/Passes/FunctionToStaticMethodPass.cs index fc0ccfba..dd1808b0 100644 --- a/src/Generator/Passes/FunctionToStaticMethodPass.cs +++ b/src/Generator/Passes/FunctionToStaticMethodPass.cs @@ -33,7 +33,7 @@ namespace CppSharp.Passes // Clean up the name of the function now that it will be a static method. var name = function.Name.Substring(@class.Name.Length); - function.ExplicityIgnored = true; + function.ExplicitlyIgnore(); // Create a new fake method so it acts as a static method. var method = new Method diff --git a/src/Generator/Passes/MoveFunctionToClassPass.cs b/src/Generator/Passes/MoveFunctionToClassPass.cs index 67fdf4e8..a06873e9 100644 --- a/src/Generator/Passes/MoveFunctionToClassPass.cs +++ b/src/Generator/Passes/MoveFunctionToClassPass.cs @@ -24,7 +24,7 @@ namespace CppSharp.Passes } if (function.IsOperator) - function.ExplicityIgnored = true; + function.ExplicitlyIgnore(); return true; } @@ -49,7 +49,7 @@ namespace CppSharp.Passes IsStatic = true }; - function.ExplicityIgnored = true; + function.ExplicitlyIgnore(); if (method.OperatorKind != CXXOperatorKind.None) { diff --git a/src/Generator/Passes/MoveOperatorToClassPass.cs b/src/Generator/Passes/MoveOperatorToClassPass.cs index c4f9e283..6e2a4cd1 100644 --- a/src/Generator/Passes/MoveOperatorToClassPass.cs +++ b/src/Generator/Passes/MoveOperatorToClassPass.cs @@ -38,7 +38,7 @@ namespace CppSharp.Passes IsStatic = true }; - function.ExplicityIgnored = true; + function.ExplicitlyIgnore(); @class.Methods.Add(method);