diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs index 0e978a8a8d9..0b7ea27c378 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs @@ -460,7 +460,38 @@ static bool ContainsReferenceToSystemRuntimeInternal (string fileName) return false; } + static Dictionary facadeReferenceDict = new Dictionary (); + + static bool RequiresFacadeAssembliesInternal (string fileName) + { + bool result; + if (facadeReferenceDict.TryGetValue (fileName, out result)) + return result; + + AssemblyDefinition assembly = null; + try { + try { + assembly = Mono.Cecil.AssemblyDefinition.ReadAssembly (fileName); + } catch { + return false; + } + foreach (var r in assembly.MainModule.AssemblyReferences) { + // Don't compare the version number since it may change depending on the version of .net standard + if (r.Name.Equals ("System.Runtime") || r.Name.Equals ("netstandard")) { + facadeReferenceDict [fileName] = true; ; + return true; + } + } + } finally { + assembly?.Dispose (); + } + facadeReferenceDict [fileName] = false; + return false; + } + static object referenceLock = new object (); + + [Obsolete ("Use RequiresFacadeAssemblies (string fileName)")] public static bool ContainsReferenceToSystemRuntime (string fileName) { lock (referenceLock) { @@ -469,6 +500,8 @@ public static bool ContainsReferenceToSystemRuntime (string fileName) } static SemaphoreSlim referenceLockAsync = new SemaphoreSlim (1, 1); + + [Obsolete ("Use RequiresFacadeAssembliesAsync (string fileName)")] public static async System.Threading.Tasks.Task ContainsReferenceToSystemRuntimeAsync (string filename) { try { @@ -479,6 +512,23 @@ public static async System.Threading.Tasks.Task ContainsReferenceToSystemR } } + internal static bool RequiresFacadeAssemblies (string fileName) + { + lock (referenceLock) { + return RequiresFacadeAssembliesInternal (fileName); + } + } + + internal static async System.Threading.Tasks.Task RequiresFacadeAssembliesAsync (string filename) + { + try { + await referenceLockAsync.WaitAsync ().ConfigureAwait (false); + return RequiresFacadeAssembliesInternal (filename); + } finally { + referenceLockAsync.Release (); + } + } + public class ManifestResource { public string Name { diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs index a3dd50f4bdc..dd5eebfb474 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs @@ -964,7 +964,7 @@ internal protected virtual async Task> OnGetReferencedAs } else { fullPath = Path.GetFullPath (refFilename.FilePath); } - if (await SystemAssemblyService.ContainsReferenceToSystemRuntimeAsync (fullPath)) { + if (await SystemAssemblyService.RequiresFacadeAssembliesAsync (fullPath)) { addFacadeAssemblies = true; break; } diff --git a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Assemblies/SystemAssemblyServiceTests.cs b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Assemblies/SystemAssemblyServiceTests.cs index d538367609b..709e1d65455 100644 --- a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Assemblies/SystemAssemblyServiceTests.cs +++ b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Assemblies/SystemAssemblyServiceTests.cs @@ -51,6 +51,22 @@ public async Task ImmutableCollectionsContainReferenceToSystemRuntimeAsync (bool Assert.That(result, Is.EqualTo(withSystemRuntime)); } + [TestCase (true, "System.Collections.Immutable.dll")] + [TestCase (false, "MonoDevelop.Core.dll")] + public void RequiresFacadeAssemblies (bool addFacades, string relativeDllPath) + { + var result = SystemAssemblyService.RequiresFacadeAssemblies (relativeDllPath); + Assert.That (result, Is.EqualTo (addFacades)); + } + + [TestCase (true, "System.Collections.Immutable.dll")] + [TestCase (false, "MonoDevelop.Core.dll")] + public async Task RequiresFacadeAssembliesAsync (bool addFacades, string relativeDllPath) + { + var result = await SystemAssemblyService.RequiresFacadeAssembliesAsync (relativeDllPath); + Assert.That (result, Is.EqualTo (addFacades)); + } + [Test] public void CheckReferencesAreOk() { diff --git a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/ProjectTests.cs b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/ProjectTests.cs index 0546831d45e..5381fff6520 100644 --- a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/ProjectTests.cs +++ b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/ProjectTests.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using NUnit.Framework; using UnitTests; @@ -816,6 +817,49 @@ public void GetDefaultNamespaceWhenProjectRootNamespaceContainsHyphen () Assert.AreEqual (expectedDefaultNamespace, result); } + [Test] + public async Task XamarinIOSProjectReferencesCollectionsImmutableNetStandardAssembly_GetReferencedAssembliesShouldIncludeNetStandard () + { + if (!Platform.IsMac) { + // NUnit platform attribute does not seem to work. + Assert.Ignore ("Only supported on Mac."); + } + + FilePath solFile = Util.GetSampleProject ("iOSImmutableCollections", "iOSImmutableCollections.sln"); + CreateNuGetConfigFile (solFile.ParentDirectory); + + var process = Process.Start ("msbuild", $"/t:Restore /p:RestoreDisableParallel=true \"{solFile}\""); + Assert.IsTrue (process.WaitForExit (120000), "Timeout restoring NuGet packages."); + Assert.AreEqual (0, process.ExitCode); + + using (var sol = (Solution) await Services.ProjectService.ReadWorkspaceItem (Util.GetMonitor (), solFile)) { + var p = (DotNetProject) sol.Items [0]; + + var refs = (await p.GetReferencedAssemblies (ConfigurationSelector.Default)).ToArray (); + + Assert.IsTrue (refs.Any (r => r.FilePath.FileName == "netstandard.dll")); + } + } + + /// + /// Clear all other package sources and just use the main NuGet package source when + /// restoring the packages for the project tests. + /// + static void CreateNuGetConfigFile (FilePath directory) + { + var fileName = directory.Combine ("NuGet.Config"); + + string xml = + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + ""; + + File.WriteAllText (fileName, xml); + } + [Test] public async Task ProjectExtensionOnModifiedCalledWhenProjectModified () { diff --git a/main/tests/test-projects/iOSImmutableCollections/iOSImmutableCollections.sln b/main/tests/test-projects/iOSImmutableCollections/iOSImmutableCollections.sln new file mode 100644 index 00000000000..c5d4fe96bb2 --- /dev/null +++ b/main/tests/test-projects/iOSImmutableCollections/iOSImmutableCollections.sln @@ -0,0 +1,17 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOSImmutableCollections", "iOSImmutableCollections\iOSImmutableCollections.csproj", "{548A1099-6C66-410D-9D72-CD5105E51D9D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {548A1099-6C66-410D-9D72-CD5105E51D9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {548A1099-6C66-410D-9D72-CD5105E51D9D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {548A1099-6C66-410D-9D72-CD5105E51D9D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {548A1099-6C66-410D-9D72-CD5105E51D9D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/main/tests/test-projects/iOSImmutableCollections/iOSImmutableCollections/MyClass.cs b/main/tests/test-projects/iOSImmutableCollections/iOSImmutableCollections/MyClass.cs new file mode 100644 index 00000000000..c628251f503 --- /dev/null +++ b/main/tests/test-projects/iOSImmutableCollections/iOSImmutableCollections/MyClass.cs @@ -0,0 +1,15 @@ + +using System; +using System.Collections.Immutable; + +namespace iOSImmutableCollections +{ + public class MyClass + { + ImmutableArray array = ImmutableArray.Empty; + + public MyClass() + { + } + } +} diff --git a/main/tests/test-projects/iOSImmutableCollections/iOSImmutableCollections/Properties/AssemblyInfo.cs b/main/tests/test-projects/iOSImmutableCollections/iOSImmutableCollections/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..159bbde0a64 --- /dev/null +++ b/main/tests/test-projects/iOSImmutableCollections/iOSImmutableCollections/Properties/AssemblyInfo.cs @@ -0,0 +1,27 @@ + +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("iOSImmutableCollections")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("Microsoft")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] diff --git a/main/tests/test-projects/iOSImmutableCollections/iOSImmutableCollections/iOSImmutableCollections.csproj b/main/tests/test-projects/iOSImmutableCollections/iOSImmutableCollections/iOSImmutableCollections.csproj new file mode 100644 index 00000000000..b164564206a --- /dev/null +++ b/main/tests/test-projects/iOSImmutableCollections/iOSImmutableCollections/iOSImmutableCollections.csproj @@ -0,0 +1,56 @@ + + + + Debug + AnyCPU + {548A1099-6C66-410D-9D72-CD5105E51D9D} + {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + iOSImmutableCollections + iOSImmutableCollections + Resources + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + iPhone Developer + true + true + true + 50484 + NSUrlSessionHandler + + + pdbonly + true + bin\Release + prompt + 4 + iPhone Developer + true + SdkOnly + NSUrlSessionHandler + + + + + + + + + + + + + + + + + + + \ No newline at end of file