Browse Source

Directly move functions instead of making methods

This keeps the original functions instead of ignoring them which helps when rearranging passes - in particular when the pass for symbols is involved.

Signed-off-by: Dimitar Dobrev <dpldobrev@protonmail.com>
pull/1261/head
Dimitar Dobrev 6 years ago
parent
commit
f6f52ac158
  1. 6
      src/Generator/Generators/CLI/CLIHeaders.cs
  2. 8
      src/Generator/Generators/CLI/CLISources.cs
  3. 76
      src/Generator/Generators/CSharp/CSharpSources.cs
  4. 99
      src/Generator/Passes/CheckOperatorsOverloads.cs
  5. 33
      src/Generator/Passes/MoveFunctionToClassPass.cs

6
src/Generator/Generators/CLI/CLIHeaders.cs

@ -222,10 +222,13 @@ namespace CppSharp.Generators.CLI
{ {
PushBlock(BlockKind.FunctionsClass); PushBlock(BlockKind.FunctionsClass);
if (!(decl is Class))
{
WriteLine("public ref class {0}", TranslationUnit.FileNameWithoutExtension); WriteLine("public ref class {0}", TranslationUnit.FileNameWithoutExtension);
WriteLine("{"); WriteLine("{");
WriteLine("public:"); WriteLine("public:");
Indent(); Indent();
}
// Generate all the function declarations for the module. // Generate all the function declarations for the module.
foreach (var function in decl.Functions) foreach (var function in decl.Functions)
@ -233,8 +236,11 @@ namespace CppSharp.Generators.CLI
GenerateFunction(function); GenerateFunction(function);
} }
if (!(decl is Class))
{
Unindent(); Unindent();
WriteLine("};"); WriteLine("};");
}
PopBlock(NewLineKind.BeforeNextBlock); PopBlock(NewLineKind.BeforeNextBlock);
} }

8
src/Generator/Generators/CLI/CLISources.cs

@ -889,11 +889,9 @@ namespace CppSharp.Generators.CLI
GenerateDeclarationCommon(function); GenerateDeclarationCommon(function);
var classSig = string.Format("{0}::{1}", QualifiedIdentifier(@namespace), Write($@"{function.ReturnType} {QualifiedIdentifier(@namespace)}::{
TranslationUnit.FileNameWithoutExtension); (@namespace is Class ? string.Empty : $@"{
TranslationUnit.FileNameWithoutExtension}::")}{function.Name}(");
Write("{0} {1}::{2}(", function.ReturnType, classSig,
function.Name);
for (var i = 0; i < function.Parameters.Count; ++i) for (var i = 0; i < function.Parameters.Count; ++i)
{ {

76
src/Generator/Generators/CSharp/CSharpSources.cs

@ -239,15 +239,19 @@ namespace CppSharp.Generators.CSharp
public virtual void GenerateNamespaceFunctionsAndVariables(DeclarationContext context) public virtual void GenerateNamespaceFunctionsAndVariables(DeclarationContext context)
{ {
var hasGlobalFunctions = !(context is Class) && context.Functions.Any(
f => f.IsGenerated);
var hasGlobalVariables = !(context is Class) && context.Variables.Any( var hasGlobalVariables = !(context is Class) && context.Variables.Any(
v => v.IsGenerated && v.Access == AccessSpecifier.Public); v => v.IsGenerated && v.Access == AccessSpecifier.Public);
if (!context.Functions.Any(f => f.IsGenerated) && !hasGlobalVariables) if (!hasGlobalFunctions && !hasGlobalVariables)
return; return;
PushBlock(BlockKind.Functions);
var parentName = SafeIdentifier(context.TranslationUnit.FileNameWithoutExtension); var parentName = SafeIdentifier(context.TranslationUnit.FileNameWithoutExtension);
PushBlock(BlockKind.Functions);
var keyword = "class"; var keyword = "class";
var classes = EnumerateClasses().ToList(); var classes = EnumerateClasses().ToList();
if (classes.FindAll(cls => cls.IsValueType && cls.Name == parentName && context.QualifiedLogicalName == cls.Namespace.QualifiedLogicalName).Any()) if (classes.FindAll(cls => cls.IsValueType && cls.Name == parentName && context.QualifiedLogicalName == cls.Namespace.QualifiedLogicalName).Any())
@ -271,12 +275,8 @@ namespace CppSharp.Generators.CSharp
UnindentAndWriteCloseBrace(); UnindentAndWriteCloseBrace();
PopBlock(NewLineKind.BeforeNextBlock); PopBlock(NewLineKind.BeforeNextBlock);
foreach (var function in context.Functions) foreach (Function function in context.Functions.Where(f => f.IsGenerated))
{
if (!function.IsGenerated) continue;
GenerateFunction(function, parentName); GenerateFunction(function, parentName);
}
foreach (var variable in context.Variables.Where( foreach (var variable in context.Variables.Where(
v => v.IsGenerated && v.Access == AccessSpecifier.Public)) v => v.IsGenerated && v.Access == AccessSpecifier.Public))
@ -443,7 +443,8 @@ namespace CppSharp.Generators.CSharp
} }
GenerateClassConstructors(@class); GenerateClassConstructors(@class);
foreach (Function function in @class.Functions.Where(f => f.IsGenerated))
GenerateFunction(function, @class.Name);
GenerateClassMethods(@class.Methods); GenerateClassMethods(@class.Methods);
GenerateClassVariables(@class); GenerateClassVariables(@class);
GenerateClassProperties(@class); GenerateClassProperties(@class);
@ -649,6 +650,10 @@ namespace CppSharp.Generators.CSharp
&& !functions.Contains(prop.SetMethod)) && !functions.Contains(prop.SetMethod))
tryAddOverload(prop.SetMethod); tryAddOverload(prop.SetMethod);
} }
functions.AddRange(from function in @class.Functions
where function.IsGenerated && !function.IsSynthetized
select function);
} }
private IEnumerable<string> GatherInternalParams(Function function, out TypePrinterResult retType) private IEnumerable<string> GatherInternalParams(Function function, out TypePrinterResult retType)
@ -2323,6 +2328,8 @@ namespace CppSharp.Generators.CSharp
if (function.SynthKind == FunctionSynthKind.DefaultValueOverload) if (function.SynthKind == FunctionSynthKind.DefaultValueOverload)
GenerateOverloadCall(function); GenerateOverloadCall(function);
else if (function.IsOperator)
GenerateOperator(function, default(QualifiedType));
else else
GenerateInternalFunctionCall(function); GenerateInternalFunctionCall(function);
@ -2650,14 +2657,14 @@ namespace CppSharp.Generators.CSharp
return delegateId; return delegateId;
} }
private void GenerateOperator(Method method, QualifiedType returnType) private void GenerateOperator(Function function, QualifiedType returnType)
{ {
if (method.SynthKind == FunctionSynthKind.ComplementOperator) if (function.SynthKind == FunctionSynthKind.ComplementOperator)
{ {
if (method.Kind == CXXMethodKind.Conversion) if (function is Method method && method.Kind == CXXMethodKind.Conversion)
{ {
// To avoid ambiguity when having the multiple inheritance pass enabled // To avoid ambiguity when having the multiple inheritance pass enabled
var paramType = method.Parameters[0].Type.SkipPointerRefs().Desugar(); var paramType = function.Parameters[0].Type.SkipPointerRefs().Desugar();
paramType = (paramType.GetPointee() ?? paramType).Desugar(); paramType = (paramType.GetPointee() ?? paramType).Desugar();
Class paramClass; Class paramClass;
Class @interface = null; Class @interface = null;
@ -2665,9 +2672,9 @@ namespace CppSharp.Generators.CSharp
@interface = paramClass.GetInterface(); @interface = paramClass.GetInterface();
var paramName = string.Format("{0}{1}", var paramName = string.Format("{0}{1}",
method.Parameters[0].Type.IsPrimitiveTypeConvertibleToRef() ? function.Parameters[0].Type.IsPrimitiveTypeConvertibleToRef() ?
"ref *" : string.Empty, "ref *" : string.Empty,
method.Parameters[0].Name); function.Parameters[0].Name);
var printedType = method.ConversionType.Visit(TypePrinter); var printedType = method.ConversionType.Visit(TypePrinter);
if (@interface != null) if (@interface != null)
{ {
@ -2679,30 +2686,45 @@ namespace CppSharp.Generators.CSharp
} }
else else
{ {
var @operator = Operators.GetOperatorOverloadPair(method.OperatorKind); var @operator = Operators.GetOperatorOverloadPair(function.OperatorKind);
WriteLine("return !({0} {1} {2});", method.Parameters[0].Name, // handle operators for comparison which return int instead of bool
@operator, method.Parameters[1].Name); Type retType = function.OriginalReturnType.Type.Desugar();
bool regular = retType.IsPrimitiveType(PrimitiveType.Bool);
if (regular)
{
WriteLine($@"return !({function.Parameters[0].Name} {
@operator} {function.Parameters[1].Name});");
}
else
{
WriteLine($@"return global::System.Convert.ToInt32(({
function.Parameters[0].Name} {@operator} {
function.Parameters[1].Name}) == 0);");
}
} }
return; return;
} }
if (method.OperatorKind == CXXOperatorKind.EqualEqual || if (function.OperatorKind == CXXOperatorKind.EqualEqual ||
method.OperatorKind == CXXOperatorKind.ExclaimEqual) function.OperatorKind == CXXOperatorKind.ExclaimEqual)
{ {
WriteLine("bool {0}Null = ReferenceEquals({0}, null);", WriteLine("bool {0}Null = ReferenceEquals({0}, null);",
method.Parameters[0].Name); function.Parameters[0].Name);
WriteLine("bool {0}Null = ReferenceEquals({0}, null);", WriteLine("bool {0}Null = ReferenceEquals({0}, null);",
method.Parameters[1].Name); function.Parameters[1].Name);
WriteLine("if ({0}Null || {1}Null)", WriteLine("if ({0}Null || {1}Null)",
method.Parameters[0].Name, method.Parameters[1].Name); function.Parameters[0].Name, function.Parameters[1].Name);
WriteLineIndent("return {0}{1}Null && {2}Null{3};", Type retType = function.OriginalReturnType.Type.Desugar();
method.OperatorKind == CXXOperatorKind.EqualEqual ? string.Empty : "!(", bool regular = retType.IsPrimitiveType(PrimitiveType.Bool);
method.Parameters[0].Name, method.Parameters[1].Name, WriteLineIndent($@"return {(regular ? string.Empty : "global::System.Convert.ToInt32(")}{
method.OperatorKind == CXXOperatorKind.EqualEqual ? string.Empty : ")"); (function.OperatorKind == CXXOperatorKind.EqualEqual ? string.Empty : "!(")}{
function.Parameters[0].Name}Null && {function.Parameters[1].Name}Null{
(function.OperatorKind == CXXOperatorKind.EqualEqual ? string.Empty : ")")}{
(regular ? string.Empty : ")")};");
} }
GenerateInternalFunctionCall(method, returnType: returnType); GenerateInternalFunctionCall(function, returnType: returnType);
} }
private void GenerateClassConstructor(Method method, Class @class) private void GenerateClassConstructor(Method method, Class @class)

99
src/Generator/Passes/CheckOperatorsOverloads.cs

@ -1,4 +1,5 @@
using System.Linq; using System.Collections.Generic;
using System.Linq;
using CppSharp.AST; using CppSharp.AST;
using CppSharp.AST.Extensions; using CppSharp.AST.Extensions;
using CppSharp.Generators; using CppSharp.Generators;
@ -65,6 +66,15 @@ namespace CppSharp.Passes
else else
CreateOperator(@class, @operator); CreateOperator(@class, @operator);
} }
foreach (var @operator in @class.Functions.Where(
f => f.IsGenerated && f.IsOperator &&
!IsValidOperatorOverload(f) && !f.IsExplicitlyGenerated))
{
Diagnostics.Debug("Invalid operator overload {0}::{1}",
@class.OriginalName, @operator.OperatorKind);
@operator.ExplicitlyIgnore();
}
} }
private static void CreateOperator(Class @class, Method @operator) private static void CreateOperator(Class @class, Method @operator)
@ -128,64 +138,85 @@ namespace CppSharp.Passes
@operator.GenerationKind = GenerationKind.Internal; @operator.GenerationKind = GenerationKind.Internal;
} }
private static void HandleMissingOperatorOverloadPair(Class @class, CXXOperatorKind op1, private static void HandleMissingOperatorOverloadPair(Class @class,
CXXOperatorKind op2) CXXOperatorKind op1, CXXOperatorKind op2)
{ {
foreach (var op in @class.Operators.Where( List<Method> methods = HandleMissingOperatorOverloadPair(
@class, @class.Operators, op1, op2);
foreach (Method @operator in methods)
{
int index = @class.Methods.IndexOf(
(Method) @operator.OriginalFunction);
@class.Methods.Insert(index, @operator);
}
List<Function> functions = HandleMissingOperatorOverloadPair(
@class, @class.Functions, op1, op2);
foreach (Method @operator in functions)
{
int index = @class.Declarations.IndexOf(
@operator.OriginalFunction);
@class.Methods.Insert(index, @operator);
}
}
private static List<T> HandleMissingOperatorOverloadPair<T>(Class @class,
IEnumerable<T> functions, CXXOperatorKind op1,
CXXOperatorKind op2) where T : Function, new()
{
List<T> fs = new List<T>();
foreach (var op in functions.Where(
o => o.OperatorKind == op1 || o.OperatorKind == op2).ToList()) o => o.OperatorKind == op1 || o.OperatorKind == op2).ToList())
{ {
int index; var missingKind = CheckMissingOperatorOverloadPair(functions,
var missingKind = CheckMissingOperatorOverloadPair(@class, out index, op1, op2, op1, op2, op.Parameters.First().Type, op.Parameters.Last().Type);
op.Parameters.First().Type, op.Parameters.Last().Type);
if (missingKind == CXXOperatorKind.None || !op.IsGenerated) if (missingKind == CXXOperatorKind.None || !op.IsGenerated)
continue; continue;
var method = new Method() var function = new T()
{ {
Name = Operators.GetOperatorIdentifier(missingKind), Name = Operators.GetOperatorIdentifier(missingKind),
Namespace = @class, Namespace = @class,
SynthKind = FunctionSynthKind.ComplementOperator, SynthKind = FunctionSynthKind.ComplementOperator,
Kind = CXXMethodKind.Operator,
OperatorKind = missingKind, OperatorKind = missingKind,
ReturnType = op.ReturnType ReturnType = op.ReturnType,
OriginalFunction = op
}; };
method.Parameters.AddRange(op.Parameters.Select( var method = function as Method;
p => new Parameter(p) { Namespace = method })); if (method != null)
method.Kind = CXXMethodKind.Operator;
@class.Methods.Insert(index, method); function.Parameters.AddRange(op.Parameters.Select(
p => new Parameter(p) { Namespace = function }));
fs.Add(function);
} }
return fs;
} }
static CXXOperatorKind CheckMissingOperatorOverloadPair(Class @class, out int index, private static CXXOperatorKind CheckMissingOperatorOverloadPair(
CXXOperatorKind op1, CXXOperatorKind op2, Type typeLeft, Type typeRight) IEnumerable<Function> functions,
CXXOperatorKind op1, CXXOperatorKind op2,
Type typeLeft, Type typeRight)
{ {
var first = @class.Operators.FirstOrDefault(o => o.IsGenerated && o.OperatorKind == op1 && var first = functions.FirstOrDefault(
o.Parameters.First().Type.Equals(typeLeft) && o.Parameters.Last().Type.Equals(typeRight)); o => o.IsGenerated && o.OperatorKind == op1 &&
var second = @class.Operators.FirstOrDefault(o => o.IsGenerated && o.OperatorKind == op2 && o.Parameters.First().Type.Equals(typeLeft) &&
o.Parameters.First().Type.Equals(typeLeft) && o.Parameters.Last().Type.Equals(typeRight)); o.Parameters.Last().Type.Equals(typeRight));
var second = functions.FirstOrDefault(
o => o.IsGenerated && o.OperatorKind == op2 &&
o.Parameters.First().Type.Equals(typeLeft) &&
o.Parameters.Last().Type.Equals(typeRight));
var hasFirst = first != null; var hasFirst = first != null;
var hasSecond = second != null; var hasSecond = second != null;
if (hasFirst && !hasSecond) return hasFirst && !hasSecond ? op2 : hasSecond && !hasFirst ? op1 : CXXOperatorKind.None;
{
index = @class.Methods.IndexOf(first);
return op2;
}
if (hasSecond && !hasFirst)
{
index = @class.Methods.IndexOf(second);
return op1;
}
index = 0;
return CXXOperatorKind.None;
} }
private bool IsValidOperatorOverload(Method @operator) private bool IsValidOperatorOverload(Function @operator)
{ {
// These follow the order described in MSDN (Overloadable Operators). // These follow the order described in MSDN (Overloadable Operators).

33
src/Generator/Passes/MoveFunctionToClassPass.cs

@ -1,4 +1,5 @@
using System.Linq; using System.Collections.Generic;
using System.Linq;
using CppSharp.AST; using CppSharp.AST;
namespace CppSharp.Passes namespace CppSharp.Passes
@ -17,6 +18,14 @@ namespace CppSharp.Passes
VisitOptions.VisitTemplateArguments = false; VisitOptions.VisitTemplateArguments = false;
} }
public override bool VisitASTContext(ASTContext context)
{
bool result = base.VisitASTContext(context);
foreach (Function movedFunction in movedFunctions)
movedFunction.OriginalNamespace.Declarations.Remove(movedFunction);
return result;
}
public override bool VisitFunctionDecl(Function function) public override bool VisitFunctionDecl(Function function)
{ {
if (!function.IsGenerated) if (!function.IsGenerated)
@ -28,23 +37,9 @@ namespace CppSharp.Passes
@class.TranslationUnit.Module != function.TranslationUnit.Module) @class.TranslationUnit.Module != function.TranslationUnit.Module)
return false; return false;
// Create a new fake method so it acts as a static method. function.Namespace = @class;
var method = new Method(function) @class.Declarations.Add(function);
{ movedFunctions.Add(function);
Namespace = @class,
OperatorKind = function.OperatorKind,
OriginalFunction = null,
IsStatic = true
};
if (method.IsOperator)
{
method.IsNonMemberOperator = true;
method.Kind = CXXMethodKind.Operator;
}
function.ExplicitlyIgnore();
@class.Methods.Add(method);
Diagnostics.Debug($"Function {function.Name} moved to class {@class.Name}"); Diagnostics.Debug($"Function {function.Name} moved to class {@class.Name}");
@ -76,5 +71,7 @@ namespace CppSharp.Passes
return @class; return @class;
} }
private HashSet<Function> movedFunctions = new HashSet<Function>();
} }
} }

Loading…
Cancel
Save