Skip to content

Commit

Permalink
Added TranslatedFunction.SpecialFunctionKind for identifying construc…
Browse files Browse the repository at this point in the history
…tors, destructors, operator overloads, and conversion overloads.

Relates to #78 and #12
  • Loading branch information
PathogenDavid committed Feb 21, 2021
1 parent 756b969 commit c828ec1
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 11 deletions.
46 changes: 35 additions & 11 deletions Biohazrd/#Declarations/TranslatedFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ public sealed record TranslatedFunction : TranslatedDeclaration
public bool IsInstanceMethod { get; }
public bool IsVirtual { get; }
public bool IsConst { get; }
public bool IsOperatorOverload { get; }
[Obsolete("Replaced by " + nameof(SpecialFunctionKind))]
public bool IsOperatorOverload => SpecialFunctionKind == SpecialFunctionKind.OperatorOverload ||SpecialFunctionKind == SpecialFunctionKind.ConversionOverload;

public SpecialFunctionKind SpecialFunctionKind { get; }

public string DllFileName { get; init; } = "TODO.dll";
public string MangledName { get; init; }
Expand All @@ -32,6 +35,7 @@ internal TranslatedFunction(TranslatedFile file, FunctionDecl function)
{ MangledName = mangling.ToString(); }

ReturnType = new ClangTypeReference(function.ReturnType);
SpecialFunctionKind = SpecialFunctionKind.None;

// Enumerate parameters
ImmutableArray<TranslatedParameter>.Builder parametersBuilder = ImmutableArray.CreateBuilder<TranslatedParameter>(function.Parameters.Count);
Expand Down Expand Up @@ -75,25 +79,35 @@ internal TranslatedFunction(TranslatedFile file, FunctionDecl function)
if (operatorOverloadInfo.Kind != PathogenOperatorOverloadKind.None)
{
Name = $"operator_{operatorOverloadInfo.Name}";
IsOperatorOverload = true;

Debug.Assert(SpecialFunctionKind == SpecialFunctionKind.None);
SpecialFunctionKind = SpecialFunctionKind.OperatorOverload;
}
else
{ IsOperatorOverload = false; }

// Handle conversion operator overloads
if (function is CXXConversionDecl)
{
Name = $"____ConversionOperator_{function.ReturnType}";
IsOperatorOverload = true;

Debug.Assert(SpecialFunctionKind == SpecialFunctionKind.None);
SpecialFunctionKind = SpecialFunctionKind.ConversionOverload;
}

// Rename constructors/destructors
// Handle constructors/destructors
if (function is CXXConstructorDecl)
{ Name = "Constructor"; }
{
Name = "Constructor";

Debug.Assert(SpecialFunctionKind == SpecialFunctionKind.None);
SpecialFunctionKind = SpecialFunctionKind.Constructor;
}
else if (function is CXXDestructorDecl)
{
Name = "Destructor";

Debug.Assert(SpecialFunctionKind == SpecialFunctionKind.None);
SpecialFunctionKind = SpecialFunctionKind.Destructor;

// clang_Cursor_getMangling returns the name of the vbase destructor (prefix ?_D), which is not what gets exported by MSVC and is thus useless for our purposes.
// We instead want the normal destructor (prefix ?1) which is the only value returned by Clang for destructors when targeting the Microsoft ABI so we use the first mangling for them.
// (In theory constructors are in a similar position where Clang uses a different Itanium-equivalent type to query the mangled name, but the C++ constructor name mangling doesn't change for these.)
Expand Down Expand Up @@ -127,14 +141,24 @@ public override IEnumerator<TranslatedDeclaration> GetEnumerator()
public override string ToString()
{
string baseString = base.ToString();

string methodNameString = SpecialFunctionKind switch
{
SpecialFunctionKind.Constructor => "Constructor",
SpecialFunctionKind.Destructor => "Destructor",
SpecialFunctionKind.OperatorOverload => "Operator Overload",
SpecialFunctionKind.ConversionOverload => "Conversion Operator",
_ => Declaration is CXXMethodDecl ? "Method" : "Function"
};

if (IsVirtual)
{ return $"Virtual Method {baseString}"; }
{ return $"Virtual {methodNameString} {baseString}"; }
else if (IsInstanceMethod)
{ return $"Instance Method {baseString}"; }
{ return $"Instance {methodNameString} {baseString}"; }
else if (Declaration is CXXMethodDecl)
{ return $"Static Method {baseString}"; }
{ return $"Static {methodNameString} {baseString}"; }
else
{ return $"Function {baseString}"; }
{ return $"{methodNameString} {baseString}"; }
}
}
}
11 changes: 11 additions & 0 deletions Biohazrd/SpecialFunctionKind.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Biohazrd
{
public enum SpecialFunctionKind
{
None,
Constructor,
Destructor,
OperatorOverload,
ConversionOverload
}
}
109 changes: 109 additions & 0 deletions Tests/Biohazrd.Tests/TranslatedFunctionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
using Biohazrd.Tests.Common;
using Xunit;

namespace Biohazrd.Tests
{
public sealed class TranslatedFunctionTests : BiohazrdTestBase
{
[Fact]
public void SpecialFunctionKind_NormalFunction()
{
TranslatedLibrary library = CreateLibrary("void Function();");
TranslatedFunction function = library.FindDeclaration<TranslatedFunction>();
Assert.Equal(SpecialFunctionKind.None, function.SpecialFunctionKind);
}

[Fact]
public void SpecialFunctionKind_NormalMethod()
{
TranslatedLibrary library = CreateLibrary
(@"
class MyClass
{
public:
void Method();
};
"
);
TranslatedFunction method = library.FindDeclaration<TranslatedRecord>().FindDeclaration<TranslatedFunction>();
Assert.Equal(SpecialFunctionKind.None, method.SpecialFunctionKind);
}

[Fact]
public void SpecialFunctionKind_Constructor()
{
TranslatedLibrary library = CreateLibrary
(@"
class MyClass
{
public:
MyClass();
};
"
);
TranslatedFunction method = library.FindDeclaration<TranslatedRecord>().FindDeclaration<TranslatedFunction>();
Assert.Equal(SpecialFunctionKind.Constructor, method.SpecialFunctionKind);
}

[Fact]
public void SpecialFunctionKind_Destructor()
{
TranslatedLibrary library = CreateLibrary
(@"
class MyClass
{
public:
~MyClass();
};
"
);
TranslatedFunction method = library.FindDeclaration<TranslatedRecord>().FindDeclaration<TranslatedFunction>();
Assert.Equal(SpecialFunctionKind.Destructor, method.SpecialFunctionKind);
}

[Fact]
public void SpecialFunctionKind_OperatorOverloadFunction()
{
TranslatedLibrary library = CreateLibrary
(@"
struct MyStruct { };
bool operator==(MyStruct, MyStruct);
"
);
TranslatedFunction function = library.FindDeclaration<TranslatedFunction>();
Assert.Equal(SpecialFunctionKind.OperatorOverload, function.SpecialFunctionKind);
}

[Fact]
public void SpecialFunctionKind_OperatorOverloadMethod()
{
TranslatedLibrary library = CreateLibrary
(@"
class MyClass
{
public:
int operator[](int i);
};
"
);
TranslatedFunction method = library.FindDeclaration<TranslatedRecord>().FindDeclaration<TranslatedFunction>();
Assert.Equal(SpecialFunctionKind.OperatorOverload, method.SpecialFunctionKind);
}

[Fact]
public void SpecialFunctionKind_ConversionOverload()
{
TranslatedLibrary library = CreateLibrary
(@"
class MyClass
{
public:
operator int();
};
"
);
TranslatedFunction method = library.FindDeclaration<TranslatedRecord>().FindDeclaration<TranslatedFunction>();
Assert.Equal(SpecialFunctionKind.ConversionOverload, method.SpecialFunctionKind);
}
}
}

0 comments on commit c828ec1

Please sign in to comment.