public void Execute() { // UNCOMMENT THIS DEBUGGER LAUNCH TO BE ABLE TO RUN A SEPARATE VS INSTANCE TO DEBUG WEAVING WHILST BUILDING // Debugger.Launch(); var submitAnalytics = System.Threading.Tasks.Task.Factory.StartNew(() => { var analytics = new RealmWeaver.Analytics(ModuleDefinition); try { analytics.SubmitAnalytics(); } catch (Exception e) { LogDebug("Error submitting analytics: " + e.Message); } }); RealmAssembly = ModuleDefinition.AssemblyResolver.Resolve("Realm"); // Note that the assembly is Realm but the namespace Realms with the s RealmObject = RealmAssembly.MainModule.GetTypes().First(x => x.Name == "RealmObject"); RealmObjectIsManagedGetter = ModuleDefinition.ImportReference(RealmObject.Properties.Single(x => x.Name == "IsManaged").GetMethod); var typeTable = new Dictionary <string, string>() { { "System.String", "String" }, { "System.Char", "Char" }, { "System.Byte", "Byte" }, { "System.Int16", "Int16" }, { "System.Int32", "Int32" }, { "System.Int64", "Int64" }, { "System.Single", "Single" }, { "System.Double", "Double" }, { "System.Boolean", "Boolean" }, { "System.DateTimeOffset", "DateTimeOffset" }, { "System.Byte[]", "ByteArray" }, { "System.Nullable`1<System.Char>", "NullableChar" }, { "System.Nullable`1<System.Byte>", "NullableByte" }, { "System.Nullable`1<System.Int16>", "NullableInt16" }, { "System.Nullable`1<System.Int32>", "NullableInt32" }, { "System.Nullable`1<System.Int64>", "NullableInt64" }, { "System.Nullable`1<System.Single>", "NullableSingle" }, { "System.Nullable`1<System.Double>", "NullableDouble" }, { "System.Nullable`1<System.Boolean>", "NullableBoolean" }, { "System.Nullable`1<System.DateTimeOffset>", "NullableDateTimeOffset" } }; // Cache of getter and setter methods for the various types. var methodTable = new Dictionary <string, Tuple <MethodReference, MethodReference> >(); var objectIdTypes = new List <string> { "System.String", "System.Char", "System.Byte", "System.Int16", "System.Int32", "System.Int64", }; var indexableTypes = new List <string>(objectIdTypes); indexableTypes.Add("System.Boolean"); indexableTypes.Add("System.DateTimeOffset"); var genericGetObjectValueReference = LookupMethodAndImport(RealmObject, "GetObjectValue"); var genericSetObjectValueReference = LookupMethodAndImport(RealmObject, "SetObjectValue"); var genericGetListValueReference = LookupMethodAndImport(RealmObject, "GetListValue"); var wovenAttributeClass = RealmAssembly.MainModule.GetTypes().First(x => x.Name == "WovenAttribute"); var wovenAttributeConstructor = ModuleDefinition.ImportReference(wovenAttributeClass.GetConstructors().First()); var wovenPropertyAttributeClass = RealmAssembly.MainModule.GetTypes().First(x => x.Name == "WovenPropertyAttribute"); var wovenPropertyAttributeConstructor = ModuleDefinition.ImportReference(wovenPropertyAttributeClass.GetConstructors().First()); CorLib = ModuleDefinition.AssemblyResolver.Resolve((AssemblyNameReference)ModuleDefinition.TypeSystem.CoreLibrary); System_Object = CorLib.MainModule.GetType("System.Object"); System_Boolean = CorLib.MainModule.GetType("System.Boolean"); System_String = ModuleDefinition.ImportReference(CorLib.MainModule.GetType("System.String")); System_Type = ModuleDefinition.ImportReference(CorLib.MainModule.GetType("System.Type")); // WARNING the GetType("System.Collections.Generic.List`1") below RETURNS NULL WHEN COMPILING A PCL // UNUSED SO COMMENT OUT var listType = ModuleDefinition.ImportReference(CorLib.MainModule.GetType("System.Collections.Generic.List`1")); var systemAssembly = ModuleDefinition.AssemblyResolver.Resolve("System"); var systemObjectModelAssembly = TryResolveAssembly("System.ObjectModel"); var propertyChangedEventArgs = LookupType("PropertyChangedEventArgs", systemObjectModelAssembly, systemAssembly); PropChangedEventArgsConstructor = ModuleDefinition.ImportReference(propertyChangedEventArgs.GetConstructors().First()); var propChangedEventHandlerDefinition = LookupType("PropertyChangedEventHandler", systemObjectModelAssembly, systemAssembly); PropChangedEventHandlerReference = ModuleDefinition.ImportReference(propChangedEventHandlerDefinition); PropChangedEventHandlerInvokeReference = ModuleDefinition.ImportReference(propChangedEventHandlerDefinition.Methods.First(x => x.Name == "Invoke")); // If the solution has a reference to PropertyChanged.Fody, let's look up the DoNotNotifyAttribute for use later. var usesPropertyChangedFody = ModuleDefinition.AssemblyReferences.Any(X => X.Name == "PropertyChanged"); if (usesPropertyChangedFody) { var propChangedAssembly = ModuleDefinition.AssemblyResolver.Resolve("PropertyChanged"); var doNotNotifyAttributeDefinition = propChangedAssembly.MainModule.GetTypes().First(X => X.Name == "DoNotNotifyAttribute"); PropChangedDoNotNotifyAttributeConstructorDefinition = ModuleDefinition.ImportReference(doNotNotifyAttributeDefinition.GetConstructors().First()); } Debug.WriteLine("Weaving file: " + ModuleDefinition.FullyQualifiedName); foreach (var type in GetMatchingTypes()) { if (type == null) { Debug.WriteLine("Weaving skipping null type from GetMatchingTypes"); continue; } Debug.WriteLine("Weaving " + type.Name); var typeImplementsPropertyChanged = type.Interfaces.Any(t => t.FullName == "System.ComponentModel.INotifyPropertyChanged"); EventDefinition propChangedEventDefinition = null; FieldDefinition propChangedFieldDefinition = null; if (typeImplementsPropertyChanged) { propChangedEventDefinition = type.Events.First(X => X.FullName.EndsWith("::PropertyChanged")); propChangedFieldDefinition = type.Fields.First(X => X.FullName.EndsWith("::PropertyChanged")); } foreach (var prop in type.Properties.Where(x => x.HasThis && !x.CustomAttributes.Any(a => a.AttributeType.Name == "IgnoredAttribute"))) { var sequencePoint = prop.GetMethod.Body.Instructions.First().SequencePoint; var columnName = prop.Name; var mapToAttribute = prop.CustomAttributes.FirstOrDefault(a => a.AttributeType.Name == "MapToAttribute"); if (mapToAttribute != null) { columnName = ((string)mapToAttribute.ConstructorArguments[0].Value); } var backingField = GetBackingField(prop); Debug.Write(" - " + prop.PropertyType.FullName + " " + prop.Name + " (Column: " + columnName + ").. "); var isIndexed = prop.CustomAttributes.Any(a => a.AttributeType.Name == "IndexedAttribute"); if (isIndexed && (!indexableTypes.Contains(prop.PropertyType.FullName))) { LogErrorPoint($"{type.Name}.{prop.Name} is marked as [Indexed] which is only allowed on integral types as well as string, bool and DateTimeOffset, not on {prop.PropertyType.FullName}", sequencePoint); continue; } var isObjectId = prop.CustomAttributes.Any(a => a.AttributeType.Name == "ObjectIdAttribute"); if (isObjectId && (!objectIdTypes.Contains(prop.PropertyType.FullName))) { LogErrorPoint($"{type.Name}.{prop.Name} is marked as [ObjectId] which is only allowed on integral and string types, not on {prop.PropertyType.FullName}", sequencePoint); continue; } if (!prop.IsAutomatic()) { if (IsRealmObject(prop.PropertyType)) { LogWarningPoint($"{type.Name}.{columnName} is not an automatic property but its type is a RealmObject which normally indicates a relationship", sequencePoint); } Debug.WriteLine("Skipped because it's not automatic."); continue; } if (typeTable.ContainsKey(prop.PropertyType.FullName)) { var typeId = prop.PropertyType.FullName + (isObjectId ? " unique" : ""); if (!methodTable.ContainsKey(typeId)) { var getter = LookupMethodAndImport(RealmObject, "Get" + typeTable[prop.PropertyType.FullName] + "Value"); var setter = LookupMethodAndImport(RealmObject, "Set" + typeTable[prop.PropertyType.FullName] + "Value" + (isObjectId ? "Unique": "")); methodTable[typeId] = Tuple.Create(getter, setter); } ReplaceGetter(prop, columnName, methodTable[typeId].Item1); ReplaceSetter(prop, backingField, columnName, methodTable[typeId].Item2, typeImplementsPropertyChanged, propChangedEventDefinition, propChangedFieldDefinition); } // else if (prop.PropertyType.Name == "IList`1" && prop.PropertyType.Namespace == "System.Collections.Generic") else if (prop.PropertyType.Name == "RealmList`1" && prop.PropertyType.Namespace == "Realms") { // RealmList allows people to declare lists only of RealmObject due to the class definition if (!prop.IsAutomatic()) { LogErrorPoint($"{type.Name}.{columnName} is not an automatic property but its type is a RealmList which normally indicates a relationship", sequencePoint); continue; } if (prop.SetMethod != null) { LogErrorPoint($"{type.Name}.{columnName} has a setter but its type is a RealmList which only supports getters", sequencePoint); continue; } var elementType = ((GenericInstanceType)prop.PropertyType).GenericArguments.Single(); ReplaceGetter(prop, columnName, new GenericInstanceMethod(genericGetListValueReference) { GenericArguments = { elementType } }); } else if (IsRealmObject(prop.PropertyType)) { if (!prop.IsAutomatic()) { LogWarningPoint($"{type.Name}.{columnName} is not an automatic property but its type is a RealmObject which normally indicates a relationship", sequencePoint); continue; } ReplaceGetter(prop, columnName, new GenericInstanceMethod(genericGetObjectValueReference) { GenericArguments = { prop.PropertyType } }); ReplaceSetter(prop, backingField, columnName, new GenericInstanceMethod(genericSetObjectValueReference) { GenericArguments = { prop.PropertyType } }, typeImplementsPropertyChanged, propChangedEventDefinition, propChangedFieldDefinition); // with casting in the RealmObject methods, should just work } else if (prop.PropertyType.FullName == "System.DateTime") { LogErrorPoint($"class '{type.Name}' field '{prop.Name}' is a DateTime which is not supported - use DateTimeOffset instead.", sequencePoint); } else { LogErrorPoint($"class '{type.Name}' field '{columnName}' is a '{prop.PropertyType}' which is not yet supported", sequencePoint); } var wovenPropertyAttribute = new CustomAttribute(wovenPropertyAttributeConstructor); wovenPropertyAttribute.ConstructorArguments.Add(new CustomAttributeArgument(System_String, backingField.Name)); prop.CustomAttributes.Add(wovenPropertyAttribute); Debug.WriteLine(""); } var wovenAttribute = new CustomAttribute(wovenAttributeConstructor); TypeReference helperType = WeaveRealmObjectHelper(type); wovenAttribute.ConstructorArguments.Add(new CustomAttributeArgument(System_Type, helperType)); type.CustomAttributes.Add(wovenAttribute); Debug.WriteLine(""); } submitAnalytics.Wait(); return; }
public void Execute() { // UNCOMMENT THIS DEBUGGER LAUNCH TO BE ABLE TO RUN A SEPARATE VS INSTANCE TO DEBUG WEAVING WHILST BUILDING // Debugger.Launch(); Debug.WriteLine("Weaving file: " + ModuleDefinition.FullyQualifiedName); var submitAnalytics = System.Threading.Tasks.Task.Factory.StartNew(() => { var analytics = new RealmWeaver.Analytics(ModuleDefinition); try { analytics.SubmitAnalytics(); } catch (Exception e) { LogDebug("Error submitting analytics: " + e.Message); } }); _references = RealmWeaver.ImportedReferences.Create(ModuleDefinition); // Cache of getter and setter methods for the various types. var methodTable = new Dictionary<string, Tuple<MethodReference, MethodReference>>(); foreach (var type in GetMatchingTypes()) { try { WeaveType(type, methodTable); } catch (Exception e) { LogError($"Unexpected error caught weaving type '{type.Name}': {e.Message}.\r\nCallstack:\r\n{e.StackTrace}"); } } submitAnalytics.Wait(); }
public void Execute() { // UNCOMMENT THIS DEBUGGER LAUNCH TO BE ABLE TO RUN A SEPARATE VS INSTANCE TO DEBUG WEAVING WHILST BUILDING // Debugger.Launch(); Debug.WriteLine("Weaving file: " + ModuleDefinition.FullyQualifiedName); var submitAnalytics = System.Threading.Tasks.Task.Factory.StartNew(() => { var analytics = new RealmWeaver.Analytics(ModuleDefinition); try { analytics.SubmitAnalytics(); } catch (Exception e) { LogDebug("Error submitting analytics: " + e.Message); } }); _realmAssembly = ModuleDefinition.AssemblyResolver.Resolve("Realm"); // Note that the assembly is Realm but the namespace Realms with the s _realmObject = _realmAssembly.MainModule.GetTypes().First(x => x.Name == "RealmObject"); _realmObjectIsManagedGetter = ModuleDefinition.ImportReference(_realmObject.Properties.Single(x => x.Name == "IsManaged").GetMethod); // Cache of getter and setter methods for the various types. var methodTable = new Dictionary <string, Tuple <MethodReference, MethodReference> >(); _genericGetObjectValueReference = LookupMethodAndImport(_realmObject, "GetObjectValue"); _genericSetObjectValueReference = LookupMethodAndImport(_realmObject, "SetObjectValue"); _genericGetListValueReference = LookupMethodAndImport(_realmObject, "GetListValue"); var wovenAttributeClass = _realmAssembly.MainModule.GetTypes().First(x => x.Name == "WovenAttribute"); _wovenAttributeConstructor = ModuleDefinition.ImportReference(wovenAttributeClass.GetConstructors().First()); var wovenPropertyAttributeClass = _realmAssembly.MainModule.GetTypes().First(x => x.Name == "WovenPropertyAttribute"); _wovenPropertyAttributeConstructor = ModuleDefinition.ImportReference(wovenPropertyAttributeClass.GetConstructors().First()); _corLib = ModuleDefinition.AssemblyResolver.Resolve((AssemblyNameReference)ModuleDefinition.TypeSystem.CoreLibrary); System_Object = _corLib.MainModule.GetType("System.Object"); System_Boolean = _corLib.MainModule.GetType("System.Boolean"); System_String = ModuleDefinition.ImportReference(_corLib.MainModule.GetType("System.String")); System_Type = ModuleDefinition.ImportReference(_corLib.MainModule.GetType("System.Type")); // WARNING the GetType("System.Collections.Generic.List`1") below RETURNS NULL WHEN COMPILING A PCL // UNUSED SO COMMENT OUT var listType = ModuleDefinition.ImportReference(_corLib.MainModule.GetType("System.Collections.Generic.List`1")); var systemAssembly = ModuleDefinition.AssemblyResolver.Resolve("System"); var systemObjectModelAssembly = TryResolveAssembly("System.ObjectModel"); var propertyChangedEventArgs = LookupType("PropertyChangedEventArgs", systemObjectModelAssembly, systemAssembly); _propChangedEventArgsConstructor = ModuleDefinition.ImportReference(propertyChangedEventArgs.GetConstructors().First()); var propChangedEventHandlerDefinition = LookupType("PropertyChangedEventHandler", systemObjectModelAssembly, systemAssembly); _propChangedEventHandlerReference = ModuleDefinition.ImportReference(propChangedEventHandlerDefinition); _propChangedEventHandlerInvokeReference = ModuleDefinition.ImportReference(propChangedEventHandlerDefinition.Methods.First(x => x.Name == "Invoke")); // If the solution has a reference to PropertyChanged.Fody, let's look up the DoNotNotifyAttribute for use later. var usesPropertyChangedFody = ModuleDefinition.AssemblyReferences.Any(X => X.Name == "PropertyChanged"); if (usesPropertyChangedFody) { var propChangedAssembly = ModuleDefinition.AssemblyResolver.Resolve("PropertyChanged"); var doNotNotifyAttributeDefinition = propChangedAssembly.MainModule.GetTypes().First(X => X.Name == "DoNotNotifyAttribute"); _propChangedDoNotNotifyAttributeConstructorDefinition = ModuleDefinition.ImportReference(doNotNotifyAttributeDefinition.GetConstructors().First()); } foreach (var type in GetMatchingTypes()) { try { WeaveType(type, methodTable); } catch (Exception e) { LogError($"Unexpected error caught weaving type '{type.Name}': {e.Message}.\r\nCallstack:\r\n{e.StackTrace}"); } } submitAnalytics.Wait(); }
public void Execute() { // UNCOMMENT THIS DEBUGGER LAUNCH TO BE ABLE TO RUN A SEPARATE VS INSTANCE TO DEBUG WEAVING WHILST BUILDING // Debugger.Launch(); Debug.WriteLine("Weaving file: " + ModuleDefinition.FullyQualifiedName); var submitAnalytics = System.Threading.Tasks.Task.Factory.StartNew(() => { var analytics = new RealmWeaver.Analytics(ModuleDefinition); try { analytics.SubmitAnalytics(); } catch (Exception e) { LogDebug("Error submitting analytics: " + e.Message); } }); _realmAssembly = AssemblyResolver.Resolve("Realm"); // Note that the assembly is Realm but the namespace Realms with the s _realmObject = _realmAssembly.MainModule.GetTypes().First(x => x.Name == "RealmObject"); _realmObjectIsManagedGetter = ModuleDefinition.ImportReference(_realmObject.Properties.Single(x => x.Name == "IsManaged").GetMethod); _realmObjectRealmGetter = ModuleDefinition.ImportReference(_realmObject.Properties.Single(p => p.Name == "Realm").GetMethod); _realmObjectRaisePropertyChanged = ModuleDefinition.ImportReference(_realmObject.Methods.Single(m => m.Name == "RaisePropertyChanged")); var realm = _realmAssembly.MainModule.GetTypes().First(x => x.Name == "Realm"); _realmAddGenericReference = ModuleDefinition.ImportReference(realm.Methods.First(x => x.Name == "Add" && x.HasGenericParameters)); // Cache of getter and setter methods for the various types. var methodTable = new Dictionary <string, Tuple <MethodReference, MethodReference> >(); _genericGetObjectValueReference = _realmObject.LookupMethodReference("GetObjectValue", ModuleDefinition); _genericSetObjectValueReference = _realmObject.LookupMethodReference("SetObjectValue", ModuleDefinition); _genericGetListValueReference = _realmObject.LookupMethodReference("GetListValue", ModuleDefinition); var preserveAttributeClass = _realmAssembly.MainModule.GetTypes().First(x => x.Name == "PreserveAttribute"); _preserveAttributeConstructor = ModuleDefinition.ImportReference(preserveAttributeClass.GetConstructors().Single(c => c.Parameters.Count == 0)); _preserveAttributeConstructorWithParams = ModuleDefinition.ImportReference(preserveAttributeClass.GetConstructors().Single(c => c.Parameters.Count == 2)); var wovenAttributeClass = _realmAssembly.MainModule.GetTypes().First(x => x.Name == "WovenAttribute"); _wovenAttributeConstructor = ModuleDefinition.ImportReference(wovenAttributeClass.GetConstructors().First()); var wovenPropertyAttributeClass = _realmAssembly.MainModule.GetTypes().First(x => x.Name == "WovenPropertyAttribute"); _wovenPropertyAttributeConstructor = ModuleDefinition.ImportReference(wovenPropertyAttributeClass.GetConstructors().First()); _corLib = AssemblyResolver.Resolve((AssemblyNameReference)ModuleDefinition.TypeSystem.CoreLibrary); _system_Object = ModuleDefinition.TypeSystem.Object; _system_Boolean = ModuleDefinition.TypeSystem.Boolean; _system_Int32 = ModuleDefinition.TypeSystem.Int32; var dateTimeOffsetType = GetTypeFromSystemAssembly("System.DateTimeOffset"); _system_DateTimeOffset = ModuleDefinition.ImportReference(dateTimeOffsetType); _system_DatetimeOffset_Op_Inequality = ModuleDefinition.ImportReference(dateTimeOffsetType.GetMethods().Single(m => m.Name == "op_Inequality")); _system_Type = ModuleDefinition.ImportReference(GetTypeFromSystemAssembly("System.Type")); var listTypeDefinition = _corLib.MainModule.GetType("System.Collections.Generic.List`1"); if (listTypeDefinition == null) { _system_IList = ModuleDefinition.ImportReference(typeof(System.Collections.Generic.List <>)); } else { _system_IList = ModuleDefinition.ImportReference(listTypeDefinition); } // If the solution has a reference to PropertyChanged.Fody, let's look up the DoNotNotifyAttribute for use later. var usesPropertyChangedFody = ModuleDefinition.AssemblyReferences.Any(X => X.Name == "PropertyChanged"); if (usesPropertyChangedFody) { var propChangedAssembly = AssemblyResolver.Resolve("PropertyChanged"); var doNotNotifyAttributeDefinition = propChangedAssembly.MainModule.GetTypes().First(X => X.Name == "DoNotNotifyAttribute"); _propChangedDoNotNotifyAttributeConstructorDefinition = ModuleDefinition.ImportReference(doNotNotifyAttributeDefinition.GetConstructors().First()); } foreach (var type in GetMatchingTypes()) { try { WeaveType(type, methodTable); } catch (Exception e) { LogError($"Unexpected error caught weaving type '{type.Name}': {e.Message}.\r\nCallstack:\r\n{e.StackTrace}"); } } submitAnalytics.Wait(); }