Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Directly move functions instead of making methods #1261

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions src/Generator/Generators/CLI/CLIHeaders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -222,19 +222,25 @@ public void GenerateFunctions(DeclarationContext decl)
{
PushBlock(BlockKind.FunctionsClass);

WriteLine("public ref class {0}", TranslationUnit.FileNameWithoutExtension);
WriteLine("{");
WriteLine("public:");
Indent();
if (!(decl is Class))
{
WriteLine("public ref class {0}", TranslationUnit.FileNameWithoutExtension);
WriteLine("{");
WriteLine("public:");
Indent();
}

// Generate all the function declarations for the module.
foreach (var function in decl.Functions)
{
GenerateFunction(function);
}

Unindent();
WriteLine("};");
if (!(decl is Class))
{
Unindent();
WriteLine("};");
}

PopBlock(NewLineKind.BeforeNextBlock);
}
Expand Down
8 changes: 3 additions & 5 deletions src/Generator/Generators/CLI/CLISources.cs
Original file line number Diff line number Diff line change
Expand Up @@ -889,11 +889,9 @@ public void GenerateFunction(Function function, DeclarationContext @namespace)

GenerateDeclarationCommon(function);

var classSig = string.Format("{0}::{1}", QualifiedIdentifier(@namespace),
TranslationUnit.FileNameWithoutExtension);

Write("{0} {1}::{2}(", function.ReturnType, classSig,
function.Name);
Write($@"{function.ReturnType} {QualifiedIdentifier(@namespace)}::{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous version was easier to read.

(@namespace is Class ? string.Empty : $@"{
TranslationUnit.FileNameWithoutExtension}::")}{function.Name}(");

for (var i = 0; i < function.Parameters.Count; ++i)
{
Expand Down
76 changes: 49 additions & 27 deletions src/Generator/Generators/CSharp/CSharpSources.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,15 +239,19 @@ private IEnumerable<Class> EnumerateClasses(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(
v => v.IsGenerated && v.Access == AccessSpecifier.Public);

if (!context.Functions.Any(f => f.IsGenerated) && !hasGlobalVariables)
if (!hasGlobalFunctions && !hasGlobalVariables)
return;

PushBlock(BlockKind.Functions);
var parentName = SafeIdentifier(context.TranslationUnit.FileNameWithoutExtension);

PushBlock(BlockKind.Functions);

var keyword = "class";
var classes = EnumerateClasses().ToList();
if (classes.FindAll(cls => cls.IsValueType && cls.Name == parentName && context.QualifiedLogicalName == cls.Namespace.QualifiedLogicalName).Any())
Expand All @@ -271,12 +275,8 @@ public virtual void GenerateNamespaceFunctionsAndVariables(DeclarationContext co
UnindentAndWriteCloseBrace();
PopBlock(NewLineKind.BeforeNextBlock);

foreach (var function in context.Functions)
{
if (!function.IsGenerated) continue;

foreach (Function function in context.Functions.Where(f => f.IsGenerated))
GenerateFunction(function, parentName);
}

foreach (var variable in context.Variables.Where(
v => v.IsGenerated && v.Access == AccessSpecifier.Public))
Expand Down Expand Up @@ -443,7 +443,8 @@ public override bool VisitClassDecl(Class @class)
}

GenerateClassConstructors(@class);

foreach (Function function in @class.Functions.Where(f => f.IsGenerated))
GenerateFunction(function, @class.Name);
GenerateClassMethods(@class.Methods);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add newline here.

GenerateClassVariables(@class);
GenerateClassProperties(@class);
Expand Down Expand Up @@ -649,6 +650,10 @@ private void GatherClassInternalFunctions(Class @class, bool includeCtors,
&& !functions.Contains(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)
Expand Down Expand Up @@ -2323,6 +2328,8 @@ public void GenerateFunction(Function function, string parentName)

if (function.SynthKind == FunctionSynthKind.DefaultValueOverload)
GenerateOverloadCall(function);
else if (function.IsOperator)
GenerateOperator(function, default(QualifiedType));
else
GenerateInternalFunctionCall(function);

Expand Down Expand Up @@ -2650,24 +2657,24 @@ private string GetVirtualCallDelegate(Method method)
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
var paramType = method.Parameters[0].Type.SkipPointerRefs().Desugar();
var paramType = function.Parameters[0].Type.SkipPointerRefs().Desugar();
paramType = (paramType.GetPointee() ?? paramType).Desugar();
Class paramClass;
Class @interface = null;
if (paramType.TryGetClass(out paramClass))
@interface = paramClass.GetInterface();

var paramName = string.Format("{0}{1}",
method.Parameters[0].Type.IsPrimitiveTypeConvertibleToRef() ?
function.Parameters[0].Type.IsPrimitiveTypeConvertibleToRef() ?
"ref *" : string.Empty,
method.Parameters[0].Name);
function.Parameters[0].Name);
var printedType = method.ConversionType.Visit(TypePrinter);
if (@interface != null)
{
Expand All @@ -2679,30 +2686,45 @@ private void GenerateOperator(Method method, QualifiedType returnType)
}
else
{
var @operator = Operators.GetOperatorOverloadPair(method.OperatorKind);
var @operator = Operators.GetOperatorOverloadPair(function.OperatorKind);

WriteLine("return !({0} {1} {2});", method.Parameters[0].Name,
@operator, method.Parameters[1].Name);
// handle operators for comparison which return int instead of bool
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;
}

if (method.OperatorKind == CXXOperatorKind.EqualEqual ||
method.OperatorKind == CXXOperatorKind.ExclaimEqual)
if (function.OperatorKind == CXXOperatorKind.EqualEqual ||
function.OperatorKind == CXXOperatorKind.ExclaimEqual)
{
WriteLine("bool {0}Null = ReferenceEquals({0}, null);",
method.Parameters[0].Name);
function.Parameters[0].Name);
WriteLine("bool {0}Null = ReferenceEquals({0}, null);",
method.Parameters[1].Name);
function.Parameters[1].Name);
WriteLine("if ({0}Null || {1}Null)",
method.Parameters[0].Name, method.Parameters[1].Name);
WriteLineIndent("return {0}{1}Null && {2}Null{3};",
method.OperatorKind == CXXOperatorKind.EqualEqual ? string.Empty : "!(",
method.Parameters[0].Name, method.Parameters[1].Name,
method.OperatorKind == CXXOperatorKind.EqualEqual ? string.Empty : ")");
function.Parameters[0].Name, function.Parameters[1].Name);
Type retType = function.OriginalReturnType.Type.Desugar();
bool regular = retType.IsPrimitiveType(PrimitiveType.Bool);
WriteLineIndent($@"return {(regular ? string.Empty : "global::System.Convert.ToInt32(")}{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could use some refactoring, and comments

(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)
Expand Down
117 changes: 74 additions & 43 deletions src/Generator/Passes/CheckOperatorsOverloads.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Linq;
using System.Collections.Generic;
using System.Linq;
using CppSharp.AST;
using CppSharp.AST.Extensions;
using CppSharp.Generators;
Expand Down Expand Up @@ -65,6 +66,15 @@ private void CheckInvalidOperators(Class @class)
else
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)
Expand Down Expand Up @@ -128,64 +138,85 @@ private void CreateIndexer(Class @class, Method @operator)
@operator.GenerationKind = GenerationKind.Internal;
}

private static void HandleMissingOperatorOverloadPair(Class @class, CXXOperatorKind op1,
CXXOperatorKind op2)
private static void HandleMissingOperatorOverloadPair(Class @class,
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)
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add some space between statements in this method

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())
{
int index;
var missingKind = CheckMissingOperatorOverloadPair(@class, out index, op1, op2,
op.Parameters.First().Type, op.Parameters.Last().Type);
var missingKind = CheckMissingOperatorOverloadPair(functions,
op1, op2, op.Parameters.First().Type, op.Parameters.Last().Type);

if (missingKind == CXXOperatorKind.None || !op.IsGenerated)
continue;

var method = new Method()
{
Name = Operators.GetOperatorIdentifier(missingKind),
Namespace = @class,
SynthKind = FunctionSynthKind.ComplementOperator,
Kind = CXXMethodKind.Operator,
OperatorKind = missingKind,
ReturnType = op.ReturnType
};

method.Parameters.AddRange(op.Parameters.Select(
p => new Parameter(p) { Namespace = method }));

@class.Methods.Insert(index, method);
var function = new T()
{
Name = Operators.GetOperatorIdentifier(missingKind),
Namespace = @class,
SynthKind = FunctionSynthKind.ComplementOperator,
OperatorKind = missingKind,
ReturnType = op.ReturnType,
OriginalFunction = op
};

var method = function as Method;
if (method != null)
method.Kind = CXXMethodKind.Operator;

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,
CXXOperatorKind op1, CXXOperatorKind op2, Type typeLeft, Type typeRight)

private static CXXOperatorKind CheckMissingOperatorOverloadPair(
IEnumerable<Function> functions,
CXXOperatorKind op1, CXXOperatorKind op2,
Type typeLeft, Type typeRight)
{
var first = @class.Operators.FirstOrDefault(o => o.IsGenerated && o.OperatorKind == op1 &&
o.Parameters.First().Type.Equals(typeLeft) && o.Parameters.Last().Type.Equals(typeRight));
var second = @class.Operators.FirstOrDefault(o => o.IsGenerated && o.OperatorKind == op2 &&
o.Parameters.First().Type.Equals(typeLeft) && o.Parameters.Last().Type.Equals(typeRight));
var first = functions.FirstOrDefault(
o => o.IsGenerated && o.OperatorKind == op1 &&
o.Parameters.First().Type.Equals(typeLeft) &&
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 hasSecond = second != null;

if (hasFirst && !hasSecond)
{
index = @class.Methods.IndexOf(first);
return op2;
}

if (hasSecond && !hasFirst)
{
index = @class.Methods.IndexOf(second);
return op1;
}

index = 0;
return CXXOperatorKind.None;
return hasFirst && !hasSecond ? op2 : hasSecond && !hasFirst ? op1 : CXXOperatorKind.None;
}

private bool IsValidOperatorOverload(Method @operator)
private bool IsValidOperatorOverload(Function @operator)
{
// These follow the order described in MSDN (Overloadable Operators).

Expand Down
Loading