public void FixAbstractMethodsStep_SkipDimMembers() { var path = Path.Combine(Path.GetFullPath(XABuildPaths.TestOutputDirectory), "temp", TestName); var step = new FixAbstractMethodsStep(); var pipeline = new Pipeline(); Directory.CreateDirectory(path); using (var context = new LinkContext(pipeline)) { context.Resolver.AddSearchDirectory(path); var myAssemblyPath = Path.Combine(path, "MyAssembly.dll"); using (var android = CreateFauxMonoAndroidAssembly()) { android.Write(Path.Combine(path, "Mono.Android.dll")); CreateAbstractIfaceImplementation(myAssemblyPath, android); } using (var assm = context.Resolve(myAssemblyPath)) { step.Process(context); var impl = assm.MainModule.GetType("MyNamespace.MyClass"); Assert.IsTrue(impl.Methods.Any(m => m.Name == "MyAbstractMethod"), "We should have generated an override for MyAbstractMethod"); Assert.IsFalse(impl.Methods.Any(m => m.Name == "MyDefaultMethod"), "We should not have generated an override for MyDefaultMethod"); } } Directory.Delete(path, true); }
public void FixAbstractMethodsStep_Explicit() { var path = Path.Combine(Path.GetFullPath(XABuildPaths.TestOutputDirectory), "temp", TestName); var step = new FixAbstractMethodsStep(new TypeDefinitionCache()); var pipeline = new Pipeline(); Directory.CreateDirectory(path); using (var context = new LinkContext(pipeline)) { context.Resolver.AddSearchDirectory(path); var myAssemblyPath = Path.Combine(path, "MyAssembly.dll"); using (var android = CreateFauxMonoAndroidAssembly()) { android.Write(Path.Combine(path, "Mono.Android.dll")); CreateExplicitInterface(myAssemblyPath, android); } using (var assm = context.Resolve(myAssemblyPath)) { step.Process(context); var impl = assm.MainModule.GetType("MyNamespace.MyClass"); Assert.AreEqual(2, impl.Methods.Count, "MyClass should contain 2 methods"); var method = impl.Methods.FirstOrDefault(m => m.Name == "MyNamespace.IMyInterface.MyMethod"); Assert.IsNotNull(method, "MyNamespace.IMyInterface.MyMethod should exist"); method = impl.Methods.FirstOrDefault(m => m.Name == "MyMissingMethod"); Assert.IsNotNull(method, "MyMissingMethod should exist"); } } Directory.Delete(path, true); }
public void FixAbstractMethodsStep_SkipDimMembers() { var step = new FixAbstractMethodsStep(); var pipeline = new Pipeline(); var context = new LinkContext(pipeline); var android = CreateFauxMonoAndroidAssembly(); var jlo = android.MainModule.GetType("Java.Lang.Object"); context.Resolver.CacheAssembly(android); var assm = AssemblyDefinition.CreateAssembly(new AssemblyNameDefinition("DimTest", new Version()), "DimTest", ModuleKind.Dll); var void_type = assm.MainModule.ImportReference(typeof(void)); // Create interface var iface = new TypeDefinition("MyNamespace", "IMyInterface", TypeAttributes.Interface); var abstract_method = new MethodDefinition("MyAbstractMethod", MethodAttributes.Abstract, void_type); var default_method = new MethodDefinition("MyDefaultMethod", MethodAttributes.Public, void_type); iface.Methods.Add(abstract_method); iface.Methods.Add(default_method); assm.MainModule.Types.Add(iface); // Create implementing class var impl = new TypeDefinition("MyNamespace", "MyClass", TypeAttributes.Public, jlo); impl.Interfaces.Add(new InterfaceImplementation(iface)); assm.MainModule.Types.Add(impl); context.Resolver.CacheAssembly(assm); step.Process(context); // We should have generated an override for MyAbstractMethod Assert.IsTrue(impl.Methods.Any(m => m.Name == "MyAbstractMethod")); // We should not have generated an override for MyDefaultMethod Assert.IsFalse(impl.Methods.Any(m => m.Name == "MyDefaultMethod")); }
public override bool RunTask() { if (SourceFiles.Length != DestinationFiles.Length) { throw new ArgumentException("source and destination count mismatch"); } var readerParameters = new ReaderParameters { ReadSymbols = true, }; var writerParameters = new WriterParameters { DeterministicMvid = Deterministic, }; using (var resolver = new DirectoryAssemblyResolver(this.CreateTaskLogger(), loadDebugSymbols: true, loadReaderParameters: readerParameters)) { // Add SearchDirectories with ResolvedAssemblies foreach (var assembly in ResolvedAssemblies) { var path = Path.GetFullPath(Path.GetDirectoryName(assembly.ItemSpec)); if (!resolver.SearchDirectories.Contains(path)) { resolver.SearchDirectories.Add(path); } } // Run the FixAbstractMethodsStep var step = new FixAbstractMethodsStep(resolver, Log); for (int i = 0; i < SourceFiles.Length; i++) { var source = SourceFiles [i]; var destination = DestinationFiles [i]; // Only run the step on "MonoAndroid" assemblies if (MonoAndroidHelper.IsMonoAndroidAssembly(source) && !MonoAndroidHelper.IsSharedRuntimeAssembly(source.ItemSpec)) { var assemblyDefinition = resolver.GetAssembly(source.ItemSpec); if (step.FixAbstractMethods(assemblyDefinition)) { Log.LogDebugMessage($"Saving modified assembly: {destination.ItemSpec}"); writerParameters.WriteSymbols = assemblyDefinition.MainModule.HasSymbols; assemblyDefinition.Write(destination.ItemSpec, writerParameters); continue; } } if (MonoAndroidHelper.CopyAssemblyAndSymbols(source.ItemSpec, destination.ItemSpec)) { Log.LogDebugMessage($"Copied: {destination.ItemSpec}"); } else { Log.LogDebugMessage($"Skipped unchanged file: {destination.ItemSpec}"); // NOTE: We still need to update the timestamp on this file, or this target would run again File.SetLastWriteTimeUtc(destination.ItemSpec, DateTime.UtcNow); } } } return(!Log.HasLoggedErrors); }
public override bool RunTask() { if (SourceFiles.Length != DestinationFiles.Length) { throw new ArgumentException("source and destination count mismatch"); } var readerParameters = new ReaderParameters { ReadSymbols = true, }; var writerParameters = new WriterParameters { DeterministicMvid = Deterministic, }; using (var resolver = new DirectoryAssemblyResolver(this.CreateTaskLogger(), loadDebugSymbols: true, loadReaderParameters: readerParameters)) { // Add SearchDirectories with ResolvedAssemblies foreach (var assembly in ResolvedAssemblies) { var path = Path.GetFullPath(Path.GetDirectoryName(assembly.ItemSpec)); if (!resolver.SearchDirectories.Contains(path)) { resolver.SearchDirectories.Add(path); } } // Set up the FixAbstractMethodsStep var step1 = new FixAbstractMethodsStep(resolver, new TypeDefinitionCache(), Log); // Set up the AddKeepAlivesStep var step2 = new MonoDroid.Tuner.AddKeepAlivesStep(new TypeDefinitionCache()); for (int i = 0; i < SourceFiles.Length; i++) { var source = SourceFiles [i]; var destination = DestinationFiles [i]; AssemblyDefinition assemblyDefinition = null; var assemblyName = Path.GetFileNameWithoutExtension(source.ItemSpec); if (!MTProfile.IsSdkAssembly(assemblyName) && !MTProfile.IsProductAssembly(assemblyName)) { assemblyDefinition = resolver.GetAssembly(source.ItemSpec); step1.CheckAppDomainUsage(assemblyDefinition, (string msg) => Log.LogMessageFromText(msg, MessageImportance.High)); } // Only run the step on "MonoAndroid" assemblies if (MonoAndroidHelper.IsMonoAndroidAssembly(source) && !MonoAndroidHelper.IsSharedRuntimeAssembly(source.ItemSpec)) { if (assemblyDefinition == null) { assemblyDefinition = resolver.GetAssembly(source.ItemSpec); } if (step1.FixAbstractMethods(assemblyDefinition) || (AddKeepAlives && step2.AddKeepAlives(assemblyDefinition))) { Log.LogDebugMessage($"Saving modified assembly: {destination.ItemSpec}"); writerParameters.WriteSymbols = assemblyDefinition.MainModule.HasSymbols; assemblyDefinition.Write(destination.ItemSpec, writerParameters); continue; } } if (MonoAndroidHelper.CopyAssemblyAndSymbols(source.ItemSpec, destination.ItemSpec)) { Log.LogDebugMessage($"Copied: {destination.ItemSpec}"); } else { Log.LogDebugMessage($"Skipped unchanged file: {destination.ItemSpec}"); // NOTE: We still need to update the timestamp on this file, or this target would run again File.SetLastWriteTimeUtc(destination.ItemSpec, DateTime.UtcNow); } } } return(!Log.HasLoggedErrors); }