Skip to content

Commit

Permalink
[generator] Fix bug 17232 - Invalid class name generated in the Libra…
Browse files Browse the repository at this point in the history
…ries.g.cs file

https://bugzilla.xamarin.com/show_bug.cgi?id=17232

* Added support for specifying library path in FieldAttribute
* Fixed generator error when Namespaces contains dots `.`
* Added error BI1042 Missing '[Field (LibraryName=value)]' for {field_pi.Name} (e.g."__Internal")
  instead of generating invalid c# code when no LibraryName is provided
  in 3rd party bindings
* Kept support for just using the system library name in FieldAttribute
  (i.e. [Field ("UnboundFooSymbol", "UIKit")]

This does not change our current generated code at all:
https://gist.github.com/dalexsoto/338464a260bc6971e7b665ca9463e8b9
  • Loading branch information
dalexsoto committed May 5, 2016
1 parent d96a159 commit c0f46af
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 12 deletions.
1 change: 1 addition & 0 deletions src/error.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
// BI1039 The selector {0} on type {1} is found multiple times with different argument length {2} : {3}.
// BI1040 The selector {0} on type {1} is found multiple times with different argument out states on argument {2}.
// BI1041 The selector {0} on type {1} is found multiple times with different argument types on argument {2} - {3} : {4}.
// BI1042 Missing '[Field (LibraryName=value)]' for {field_pi.Name} (e.g."__Internal")
// BI11xx warnings
// BI1101 Trying to use a string as a [Target]
// BI1102 Using the deprecated EventArgs for a delegate signature in {0}.{1}, please use DelegateName instead
Expand Down
5 changes: 3 additions & 2 deletions src/generator-enums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using XamCore.Foundation;
using XamCore.ObjCRuntime;
Expand Down Expand Up @@ -96,8 +97,8 @@ void GenerateEnum (Type type)
library_name = library_name.Substring (ns.Prefix.Length + 1);

// there might not be any other fields in the framework
if (!libraries.Contains (library_name))
libraries.Add (library_name);
if (!libraries.Any (l => l.Item1 == library_name))
libraries.Add (new Tuple <string, string> (library_name, null));
}

if (error != null) {
Expand Down
67 changes: 57 additions & 10 deletions src/generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1485,7 +1485,7 @@ public partial class Generator : IMemberGatherer {
Dictionary<Type,TrampolineInfo> trampolines = new Dictionary<Type,TrampolineInfo> ();
Dictionary<Type,int> trampolines_generic_versions = new Dictionary<Type,int> ();
Dictionary<Type,Type> notification_event_arg_types = new Dictionary<Type,Type> ();
List <string> libraries = new List <string> ();
List<Tuple<string, string>> libraries = new List<Tuple<string, string>> (); // <LibraryName, libraryPath>

List<Tuple<string, ParameterInfo[]>> async_result_types = new List<Tuple <string, ParameterInfo[]>> ();
HashSet<string> async_result_types_emitted = new HashSet<string> ();
Expand Down Expand Up @@ -3004,7 +3004,33 @@ void GenerateTrampolinesForQueue (TrampolineInfo [] queue)
print ("}} /* class {0} */", ti.NativeInvokerName);
}
}


// We need to check against the user using just UIKit (and friends) in the FieldAttribute
// so we need to reflect the libraries contained in our Constants class and do the mapping
// we will return the system library path if found
bool IsNotSystemLibrary (string library_name)
{
string library_path = null;
return IsNotSystemLibrary (library_name, ref library_path);
}

bool IsNotSystemLibrary (string library_name, ref string library_path)
{
var libSuffixedName = $"{library_name}Library";
var constType = typeof (
#if XAMCORE_2_0
XamCore.ObjCRuntime.Constants);
#else
XamCore.Constants);
#endif
var field = constType.GetFields (BindingFlags.Public | BindingFlags.Static).FirstOrDefault (f => f.Name == libSuffixedName);
if (field == null)
return true;

library_path = (string) field.GetValue (null);
return false;
}

void GenerateLibraryHandles ()
{
sw = GetOutputStream ("ObjCRuntime", "Libraries");
Expand All @@ -3013,10 +3039,14 @@ void GenerateLibraryHandles ()
print ("namespace {0} {{", ns.CoreObjCRuntime); indent++;
print ("[CompilerGenerated]");
print ("static partial class Libraries {"); indent++;
foreach (string library_name in libraries.OrderBy (v => v)) {
print ("static public class {0} {{", library_name); indent++;
foreach (var library_info in libraries.OrderBy (v => v.Item1)) {
var library_name = library_info.Item1; // Getting the info from the tuple for readability
var library_path = library_info.Item2; // Getting the info from the tuple for readability
print ("static public class {0} {{", library_name.Replace (".", string.Empty)); indent++;
if (BindThirdPartyLibrary && library_name == "__Internal") {
print ("static public readonly IntPtr Handle = Dlfcn.dlopen (null, 0);");
} else if (BindThirdPartyLibrary && library_path != null && IsNotSystemLibrary (library_name)) {
print ($"static public readonly IntPtr Handle = Dlfcn.dlopen (\"{library_path}\", 0);");
} else {
print ("static public readonly IntPtr Handle = Dlfcn.dlopen (Constants.{0}Library, 0);", library_name);
}
Expand Down Expand Up @@ -6228,6 +6258,7 @@ public void Generate (Type type)
foreach (var field_pi in field_exports.OrderBy (f => f.Name)) {
var fieldAttr = (FieldAttribute) field_pi.GetCustomAttributes (typeof (FieldAttribute), true) [0];
string library_name;
string library_path = null;

if (fieldAttr.LibraryName != null){
// Remapped
Expand All @@ -6241,19 +6272,35 @@ public void Generate (Type type)
library_name = CoreServicesMap;
break;
}
}
} else {
// we get something in LibraryName from FieldAttribute so we asume
// it is a path to a library, so we save the path and change library name
// to a valid identifier if needed
library_path = library_name;
if (library_name.Contains ("/")) {
var lastSlashIdx = library_name.LastIndexOf ("/");
library_name = library_name.Substring (lastSlashIdx + 1);
}
if (library_name.Contains ("."))
library_name = library_name.Replace (".", string.Empty);
}
} else if (BindThirdPartyLibrary) {
// User should provide a LibraryName
throw new BindingException (1042, true, $"Missing '[Field (LibraryName=value)]' for {field_pi.Name} (e.g.\"__Internal\")");
} else {
library_name = type.Namespace;
// note: not every binding namespace will start with ns.Prefix (e.g. MonoTouch.)
if (!String.IsNullOrEmpty (ns.Prefix) && library_name.StartsWith (ns.Prefix))
if (!String.IsNullOrEmpty (ns.Prefix) && library_name.StartsWith (ns.Prefix)) {
library_name = library_name.Substring (ns.Prefix.Length + 1);
library_name = library_name.Replace (".", string.Empty); // Remove dots from namespaces
}
}

if (!libraries.Contains (library_name)) {
libraries.Add (library_name);
if (!libraries.Any (l => l.Item1 == library_name)) {
libraries.Add (new Tuple<string, string> (library_name, library_path));
}
bool is_unified_internal = field_pi.IsUnifiedInternal ();

string fieldTypeName = FormatType (field_pi.DeclaringType, field_pi.PropertyType);
// Value types we dont cache for now, to avoid Nullable<T>
if (!field_pi.PropertyType.IsValueType) {
Expand All @@ -6263,7 +6310,7 @@ public void Generate (Type type)
}

PrintPreserveAttribute (field_pi);
print ("[Field (\"{0}\", \"{1}\")]", fieldAttr.SymbolName, library_name);
print ("[Field (\"{0}\", \"{1}\")]", fieldAttr.SymbolName, library_path ?? library_name);
PrintPlatformAttributes (field_pi);
if (Generator.HasAttribute (field_pi, typeof (AdvancedAttribute))){
print ("[EditorBrowsable (EditorBrowsableState.Advanced)]");
Expand Down

0 comments on commit c0f46af

Please sign in to comment.