[object][processor] Filter and warn about unsupported C# features/types (#117)
This allow the tool to produce something on existing binaries, which will make testing easier as we go forward.
This commit is contained in:
Родитель
4c60ece830
Коммит
2f52100568
|
@ -48,21 +48,81 @@ The tool could not find the currently selected Xcode location using the `xcode-s
|
|||
|
||||
The architecture in the error message is not valid for the targeted platform. Please verify that the --abi option is passed a valid architecture.
|
||||
|
||||
<h3><a name="EM0009"/>EM0009: The feature `X` is not currently implemented by the generator</h3>
|
||||
|
||||
This is a known issue that we intend to fix in a future release of the generator. Contributions are welcome.
|
||||
|
||||
<h3><a name="EM0099"/>EM0099: Internal error *. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues).</h3>
|
||||
|
||||
This error message is reported when an internal consistency check in the Embeddinator-4000 fails.
|
||||
|
||||
This indicates a bug in the Embeddinator-4000; please file a bug report at [https://github.com/mono/Embeddinator-4000/issues](https://github.com/mono/Embeddinator-4000/issues) with a test case.
|
||||
|
||||
# EM1xxx: code generation
|
||||
|
||||
<h3><a name="EM1000"/>EM1000: The feature `X` is not currently implemented by the generator</h3>
|
||||
<!-- 1xxx: code processing -->
|
||||
|
||||
This is a known issue that we intend to fix in a future release of the generator. Contributions are welcome.
|
||||
# EM1xxx: Code Processing
|
||||
|
||||
<h3><a name="EM1010"/>Type `T` is not generated because `X` are not supported.</h3>
|
||||
|
||||
This is a **warning** that the type `T` will be ignored (i.e. nothing will be generated) because it uses `X`, a feature that is not supported.
|
||||
|
||||
Note: Supported features will evolve with new versions of the tool.
|
||||
|
||||
|
||||
<h3><a name="EM1011"/>Type `T` is not generated because it lacks a native counterpart.</h3>
|
||||
|
||||
This is a **warning** that the type `T` will be ignored (i.e. nothing will be generated) because it uses it expose something from the .NET framework that has no counterpart in the native platform.
|
||||
|
||||
|
||||
<h3><a name="EM1011"/>Type `T` is not generated because it lacks marshaling code with a native counterpart.</h3>
|
||||
|
||||
This is a **warning** that the type `T` will be ignored (i.e. nothing will be generated) because it uses it expose something from the .NET framework that requires extra marshaling.
|
||||
|
||||
Note: This is something that is might get supported, with some limitations, in a future version of the tool.
|
||||
|
||||
|
||||
<h3><a name="EM1020"/>Constructor `C` is not generated because of parameter type `T` is not supported.</h3>
|
||||
|
||||
This is a **warning** that the constructor `C` will be ignored (i.e. nothing will be generated) because a parameter of type `T` is not supported.
|
||||
|
||||
There should be an earlier warning giving more information why type `T` is not supported.
|
||||
|
||||
Note: Supported features will evolve with new versions of the tool.
|
||||
|
||||
|
||||
<h3><a name="EM1030"/>Method `M` is not generated because return type `T` is not supported.</h3>
|
||||
|
||||
This is a **warning** that the method `M` will be ignored (i.e. nothing will be generated) because it's return type `T` is not supported.
|
||||
|
||||
There should be an earlier warning giving more information why type `T` is not supported.
|
||||
|
||||
Note: Supported features will evolve with new versions of the tool.
|
||||
|
||||
|
||||
<h3><a name="EM1031"/>Method `M` is not generated because of parameter type `T` is not supported.</h3>
|
||||
|
||||
This is a **warning** that the method `M` will be ignored (i.e. nothing will be generated) because a parameter of type `T` is not supported.
|
||||
|
||||
There should be an earlier warning giving more information why type `T` is not supported.
|
||||
|
||||
Note: Supported features will evolve with new versions of the tool.
|
||||
|
||||
|
||||
<h3><a name="EM1040"/>Property `P` is not generated because of parameter type `T` is not supported.</h3>
|
||||
|
||||
This is a **warning** that the property `P` will be ignored (i.e. nothing will be generated) because the exposed type `T` is not supported.
|
||||
|
||||
There should be an earlier warning giving more information why type `T` is not supported.
|
||||
|
||||
Note: Supported features will evolve with new versions of the tool.
|
||||
|
||||
|
||||
<!-- 2xxx: code generation -->
|
||||
|
||||
# EM2xxx: Code Generation
|
||||
|
||||
<!-- 1xxx: code generation -->
|
||||
|
||||
<!-- 2xxx: reserved -->
|
||||
<!-- 3xxx: reserved -->
|
||||
<!-- 4xxx: reserved -->
|
||||
<!-- 5xxx: reserved -->
|
||||
|
|
|
@ -107,7 +107,7 @@ namespace Embeddinator {
|
|||
Console.WriteLine ("Done");
|
||||
return result;
|
||||
} catch (NotImplementedException e) {
|
||||
throw new EmbeddinatorException (1000, $"The feature `{e.Message}` is not currently supported by the tool");
|
||||
throw new EmbeddinatorException (9, $"The feature `{e.Message}` is not currently supported by the tool");
|
||||
}
|
||||
default:
|
||||
throw ErrorHelper.CreateError (99, "Internal error: invalid action {0}. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues)", action);
|
||||
|
|
|
@ -307,6 +307,7 @@
|
|||
<Compile Include="ErrorHelper.cs" />
|
||||
<Compile Include="Version.generated.cs" />
|
||||
<Compile Include="objcgenerator-helpers.cs" />
|
||||
<Compile Include="objcgenerator-processor.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="support\" />
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using IKVM.Reflection;
|
||||
using Type = IKVM.Reflection.Type;
|
||||
|
||||
using Embeddinator;
|
||||
|
||||
namespace ObjC {
|
||||
|
||||
public partial class ObjCGenerator {
|
||||
|
||||
List<Exception> delayed = new List<Exception> ();
|
||||
HashSet<Type> unsupported = new HashSet<Type> ();
|
||||
|
||||
bool IsSupported (Type t)
|
||||
{
|
||||
if (t.IsByRef)
|
||||
return IsSupported (t.GetElementType ());
|
||||
|
||||
if (unsupported.Contains (t))
|
||||
return false;
|
||||
|
||||
// FIXME enums
|
||||
if (t.IsEnum) {
|
||||
delayed.Add (ErrorHelper.CreateWarning (1010, $"Type `{t}` is not generated because `enums` are not supported."));
|
||||
unsupported.Add (t);
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME protocols
|
||||
if (t.IsInterface) {
|
||||
delayed.Add (ErrorHelper.CreateWarning (1010, $"Type `{t}` is not generated because `interfaces` are not supported."));
|
||||
unsupported.Add (t);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (t.IsGenericParameter || t.IsGenericType) {
|
||||
delayed.Add (ErrorHelper.CreateWarning (1010, $"Type `{t}` is not generated because `generics` are not supported."));
|
||||
unsupported.Add (t);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (t.Namespace) {
|
||||
case "System":
|
||||
switch (t.Name) {
|
||||
case "Object": // we cannot accept arbitrary NSObject (which we might not have bound) into mono
|
||||
case "Exception":
|
||||
case "IFormatProvider":
|
||||
case "Type":
|
||||
delayed.Add (ErrorHelper.CreateWarning (1011, $"Type `{t}` is not generated because it lacks a native counterpart."));
|
||||
unsupported.Add (t);
|
||||
return false;
|
||||
case "DateTime": // FIXME: NSDateTime
|
||||
case "Decimal": // FIXME: NSDecimal
|
||||
case "TimeSpan":
|
||||
delayed.Add (ErrorHelper.CreateWarning (1012, $"Type `{t}` is not generated because it lacks a marshaling code with a native counterpart."));
|
||||
unsupported.Add (t);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected IEnumerable<Type> GetTypes (Assembly a)
|
||||
{
|
||||
foreach (var t in a.GetTypes ()) {
|
||||
if (!t.IsPublic)
|
||||
continue;
|
||||
|
||||
if (!IsSupported (t))
|
||||
continue;
|
||||
|
||||
yield return t;
|
||||
}
|
||||
}
|
||||
|
||||
protected IEnumerable<ConstructorInfo> GetConstructors (Type t)
|
||||
{
|
||||
foreach (var ctor in t.GetConstructors ()) {
|
||||
// .cctor not to be called directly by native code
|
||||
if (ctor.IsStatic)
|
||||
continue;
|
||||
if (!ctor.IsPublic)
|
||||
continue;
|
||||
|
||||
bool pcheck = true;
|
||||
foreach (var p in ctor.GetParameters ()) {
|
||||
var pt = p.ParameterType;
|
||||
if (!IsSupported (pt)) {
|
||||
delayed.Add (ErrorHelper.CreateWarning (1020, $"Constructor `{ctor}` is not generated because of parameter type `{pt}` is not supported."));
|
||||
pcheck = false;
|
||||
}
|
||||
}
|
||||
if (!pcheck)
|
||||
continue;
|
||||
|
||||
yield return ctor;
|
||||
}
|
||||
}
|
||||
|
||||
protected IEnumerable<MethodInfo> GetMethods (Type t)
|
||||
{
|
||||
foreach (var mi in t.GetMethods (BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)) {
|
||||
if (!mi.IsPublic)
|
||||
continue;
|
||||
|
||||
var rt = mi.ReturnType;
|
||||
if (!IsSupported (rt)) {
|
||||
delayed.Add (ErrorHelper.CreateWarning (1030, $"Method `{mi}` is not generated because return type `{rt}` is not supported."));
|
||||
continue;
|
||||
}
|
||||
|
||||
bool pcheck = true;
|
||||
foreach (var p in mi.GetParameters ()) {
|
||||
var pt = p.ParameterType;
|
||||
if (!IsSupported (pt)) {
|
||||
delayed.Add (ErrorHelper.CreateWarning (1031, $"Method `{mi}` is not generated because of parameter type `{pt}` is not supported."));
|
||||
pcheck = false;
|
||||
}
|
||||
}
|
||||
if (!pcheck)
|
||||
continue;
|
||||
|
||||
yield return mi;
|
||||
}
|
||||
}
|
||||
|
||||
protected IEnumerable<PropertyInfo> GetProperties (Type t)
|
||||
{
|
||||
foreach (var pi in t.GetProperties (BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)) {
|
||||
var pt = pi.PropertyType;
|
||||
if (!IsSupported (pt)) {
|
||||
delayed.Add (ErrorHelper.CreateWarning (1040, $"Property `{pi}` is not generated because of parameter type `{pt}` is not supported."));
|
||||
continue;
|
||||
}
|
||||
yield return pi;
|
||||
}
|
||||
}
|
||||
|
||||
List<Type> types = new List<Type> ();
|
||||
Dictionary<Type, List<ConstructorInfo>> ctors = new Dictionary<Type, List<ConstructorInfo>> ();
|
||||
Dictionary<Type, List<MethodInfo>> methods = new Dictionary<Type, List<MethodInfo>> ();
|
||||
Dictionary<Type, List<PropertyInfo>> properties = new Dictionary<Type, List<PropertyInfo>> ();
|
||||
|
||||
public override void Process (IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
foreach (var a in assemblies) {
|
||||
foreach (var t in GetTypes (a)) {
|
||||
// gather types for forward declarations
|
||||
types.Add (t);
|
||||
|
||||
var constructors = GetConstructors (t).OrderBy ((arg) => arg.ParameterCount).ToList ();
|
||||
ctors.Add (t, constructors);
|
||||
|
||||
var meths = GetMethods (t).OrderBy ((arg) => arg.Name).ToList ();
|
||||
methods.Add (t, meths);
|
||||
|
||||
var props = new List<PropertyInfo> ();
|
||||
foreach (var pi in GetProperties (t)) {
|
||||
var getter = pi.GetGetMethod ();
|
||||
var setter = pi.GetSetMethod ();
|
||||
// setter only property are valid in .NET and we need to generate a method in ObjC (there's no writeonly properties)
|
||||
if (getter == null)
|
||||
continue;
|
||||
// we can do better than methods for the more common cases (readonly and readwrite)
|
||||
meths.Remove (getter);
|
||||
meths.Remove (setter);
|
||||
props.Add (pi);
|
||||
}
|
||||
props = props.OrderBy ((arg) => arg.Name).ToList ();
|
||||
properties.Add (t, props);
|
||||
}
|
||||
}
|
||||
types = types.OrderBy ((arg) => arg.FullName).OrderBy ((arg) => types.Contains (arg.BaseType)).ToList ();
|
||||
Console.WriteLine ($"\t{types.Count} types found");
|
||||
|
||||
ErrorHelper.Show (delayed);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,60 +16,6 @@ namespace ObjC {
|
|||
static TextWriter headers = new StringWriter ();
|
||||
static TextWriter implementation = new StringWriter ();
|
||||
|
||||
static ParameterInfo [] NoParameters = new ParameterInfo [0];
|
||||
|
||||
List<Type> types = new List<Type> ();
|
||||
Dictionary<Type, List<ConstructorInfo>> ctors = new Dictionary<Type, List<ConstructorInfo>> ();
|
||||
Dictionary<Type, List<MethodInfo>> methods = new Dictionary<Type, List<MethodInfo>> ();
|
||||
Dictionary<Type, List<PropertyInfo>> properties = new Dictionary<Type, List<PropertyInfo>> ();
|
||||
|
||||
public override void Process (IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
foreach (var a in assemblies) {
|
||||
foreach (var t in a.GetTypes ()) {
|
||||
if (!t.IsPublic)
|
||||
continue;
|
||||
// gather types for forward declarations
|
||||
types.Add (t);
|
||||
|
||||
var constructors = new List<ConstructorInfo> ();
|
||||
foreach (var ctor in t.GetConstructors ()) {
|
||||
// .cctor not to be called directly by native code
|
||||
if (ctor.IsStatic)
|
||||
continue;
|
||||
if (!ctor.IsPublic)
|
||||
continue;
|
||||
constructors.Add (ctor);
|
||||
}
|
||||
constructors = constructors.OrderBy ((arg) => arg.ParameterCount).ToList ();
|
||||
ctors.Add (t, constructors);
|
||||
|
||||
var meths = new List<MethodInfo> ();
|
||||
foreach (var mi in t.GetMethods (BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)) {
|
||||
meths.Add (mi);
|
||||
}
|
||||
methods.Add (t, meths);
|
||||
|
||||
var props = new List<PropertyInfo> ();
|
||||
foreach (var pi in t.GetProperties (BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)) {
|
||||
var getter = pi.GetGetMethod ();
|
||||
var setter = pi.GetSetMethod ();
|
||||
// setter only property are valid in .NET and we need to generate a method in ObjC (there's no writeonly properties)
|
||||
if (getter == null)
|
||||
continue;
|
||||
// we can do better than methods for the more common cases (readonly and readwrite)
|
||||
meths.Remove (getter);
|
||||
meths.Remove (setter);
|
||||
props.Add (pi);
|
||||
}
|
||||
props = props.OrderBy ((arg) => arg.Name).ToList ();
|
||||
properties.Add (t, props);
|
||||
}
|
||||
}
|
||||
types = types.OrderBy ((arg) => arg.FullName).OrderBy ((arg) => types.Contains (arg.BaseType)).ToList ();
|
||||
Console.WriteLine ($"\t{types.Count} types found");
|
||||
}
|
||||
|
||||
public override void Generate (IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
headers.WriteLine ("#include \"embeddinator.h\"");
|
||||
|
@ -340,7 +286,11 @@ namespace ObjC {
|
|||
implementation.WriteLine ($"\t\t__args [{i}] = &{p.Name};");
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException ($"Converting type {p.ParameterType.FullName} to mono code");
|
||||
if (types.Contains (pt))
|
||||
implementation.WriteLine ($"\t\t__args [{i}] = {p.Name};");
|
||||
else
|
||||
throw new NotImplementedException ($"Converting type {pt.FullName} to mono code");
|
||||
break;
|
||||
}
|
||||
}
|
||||
postInvoke = post.ToString ();
|
||||
|
@ -569,15 +519,13 @@ namespace ObjC {
|
|||
switch (t.Namespace) {
|
||||
case "System":
|
||||
switch (t.Name) {
|
||||
case "Object":
|
||||
return "object";
|
||||
case "Void":
|
||||
return "void";
|
||||
default:
|
||||
throw new NotImplementedException ($"Converting type {t.Name} to a mono type name");
|
||||
return "object";
|
||||
}
|
||||
default:
|
||||
throw new NotImplementedException ($"Converting type {t.Name} to a mono type name");
|
||||
return "object";
|
||||
}
|
||||
case TypeCode.Boolean:
|
||||
return "bool";
|
||||
|
|
Загрузка…
Ссылка в новой задаче