From 08db8d79bc782a5be0e3c6293580a308c0ad2746 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 6 Aug 2021 17:40:15 -0700 Subject: [PATCH] Update implicit global usings feature * Undo changes to VB projects * For C#, projects use the `Using` itemgroup to generate global usings. Support aliasing and static imports with attributes. * Use ImplicitUsings to determine if SDK-specific namespaces are imported by default. --- src/BlazorWasmSdk/Sdk/Sdk.props | 10 +- src/BlazorWasmSdk/Sdk/Sdk.targets | 1 - .../GenerateGlobalUsings.cs | 117 +++++++++++++++ ...Microsoft.NET.GenerateGlobalUsings.targets | 57 ++++++++ ...T.GenerateImplicitNamespaceImports.targets | 57 -------- .../targets/Microsoft.NET.Sdk.CSharp.props | 11 ++ .../Microsoft.NET.Sdk.DefaultItems.props | 45 ------ .../Microsoft.NET.Sdk.VisualBasic.targets | 24 ++++ .../targets/Microsoft.NET.Sdk.targets | 3 +- ...GivenThatWeWantToBuildASelfContainedApp.cs | 4 +- ...eWantToGenerateGlobalUsings_BlazorWasm.cs} | 40 ++---- ...hatWeWantToGenerateGlobalUsings_DotNet.cs} | 134 +++++++++--------- ...hatWeWantToGenerateGlobalUsings_WebApp.cs} | 51 +++---- ...hatWeWantToGenerateGlobalUsings_Worker.cs} | 42 +++--- .../GivenDotnetRunRunsCsProj.cs | 1 + .../GivenDotnetWorkloadList.cs | 1 + .../dotnet.Tests/GivenThatICareAboutVBApps.cs | 26 +--- src/WebSdk/Web/Sdk/Sdk.props | 22 ++- src/WebSdk/Web/Sdk/Sdk.targets | 1 - .../Targets/Microsoft.NET.Sdk.Worker.props | 12 +- .../Targets/Microsoft.NET.Sdk.Worker.targets | 1 - 21 files changed, 350 insertions(+), 310 deletions(-) create mode 100644 src/Tasks/Microsoft.NET.Build.Tasks/GenerateGlobalUsings.cs create mode 100644 src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.GenerateGlobalUsings.targets delete mode 100644 src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.GenerateImplicitNamespaceImports.targets rename src/Tests/Microsoft.NET.Build.Tests/{GivenThatWeWantToGenerateImplicitNamespaceImports_BlazorWasm.cs => GivenThatWeWantToGenerateGlobalUsings_BlazorWasm.cs} (69%) rename src/Tests/Microsoft.NET.Build.Tests/{GivenThatWeWantToGenerateImplicitNamespaceImports_DotNet.cs => GivenThatWeWantToGenerateGlobalUsings_DotNet.cs} (55%) rename src/Tests/Microsoft.NET.Build.Tests/{GivenThatWeWantToGenerateImplicitNamespaceImports_WebApp.cs => GivenThatWeWantToGenerateGlobalUsings_WebApp.cs} (70%) rename src/Tests/Microsoft.NET.Build.Tests/{GivenThatWeWantToGenerateImplicitNamespaceImports_Worker.cs => GivenThatWeWantToGenerateGlobalUsings_Worker.cs} (76%) diff --git a/src/BlazorWasmSdk/Sdk/Sdk.props b/src/BlazorWasmSdk/Sdk/Sdk.props index ad4f7eea628b..4b8eeabe2787 100644 --- a/src/BlazorWasmSdk/Sdk/Sdk.props +++ b/src/BlazorWasmSdk/Sdk/Sdk.props @@ -20,11 +20,9 @@ Copyright (c) .NET Foundation. All rights reserved. - - - - + + + + diff --git a/src/BlazorWasmSdk/Sdk/Sdk.targets b/src/BlazorWasmSdk/Sdk/Sdk.targets index ed448c68a996..4dbd28518446 100644 --- a/src/BlazorWasmSdk/Sdk/Sdk.targets +++ b/src/BlazorWasmSdk/Sdk/Sdk.targets @@ -13,7 +13,6 @@ Copyright (c) .NET Foundation. All rights reserved. <_BlazorWebAssemblyTargetsFile Condition="'$(_BlazorWebAssemblyTargetsFile)' == ''">$(MSBuildThisFileDirectory)..\targets\Microsoft.NET.Sdk.BlazorWebAssembly.Current.targets - false diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/GenerateGlobalUsings.cs b/src/Tasks/Microsoft.NET.Build.Tasks/GenerateGlobalUsings.cs new file mode 100644 index 000000000000..d2984db59fda --- /dev/null +++ b/src/Tasks/Microsoft.NET.Build.Tasks/GenerateGlobalUsings.cs @@ -0,0 +1,117 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Build.Framework; + +namespace Microsoft.NET.Build.Tasks +{ + public sealed class GenerateGlobalUsings : TaskBase + { + [Required] + public ITaskItem[] Usings { get; set; } + + [Output] + public string[] Lines { get; set; } + + protected override void ExecuteCore() + { + if (Usings.Length == 0) + { + Lines = Array.Empty(); + return; + } + + var usings = Usings.Select(UsingInfo.Read) + .OrderBy(static k => k, UsingInfoComparer.Instance) + .Distinct(UsingInfoComparer.Instance); + + var lines = new string[Usings.Length + 1]; + lines[0] = "// "; + + var index = 1; + var lineBuilder = new StringBuilder(); + foreach (var @using in usings) + { + lineBuilder.Clear(); + lineBuilder.Append("global using "); + + if (@using.Static) + { + lineBuilder.Append("static "); + } + + if (!string.IsNullOrEmpty(@using.Alias)) + { + lineBuilder.Append(@using.Alias) + .Append(" = "); + } + + lineBuilder.Append("global::") + .Append(@using.Namespace) + .Append(';'); + + lines[index++] = lineBuilder.ToString(); + } + + Lines = lines; + } + + private readonly struct UsingInfo + { + public static UsingInfo Read(ITaskItem taskItem) + { + return new UsingInfo( + taskItem.ItemSpec, + taskItem.GetBooleanMetadata("Static") == true, + taskItem.GetMetadata("Alias")); + } + + private UsingInfo(string @namespace, bool @static, string alias) + { + Namespace = @namespace; + Static = @static; + Alias = alias; + } + + public string Namespace { get; } + public bool Static { get; } + public string Alias { get; } + } + + private sealed class UsingInfoComparer : IComparer, IEqualityComparer + { + public static readonly UsingInfoComparer Instance = new(); + + public int Compare(UsingInfo x, UsingInfo y) + { + var @static = x.Static.CompareTo(y.Static); + if (@static != 0) + { + return @static; + } + + var alias = x.Alias.CompareTo(y.Alias); + if (alias != 0) + { + return alias; + } + + return StringComparer.Ordinal.Compare(x.Namespace, y.Namespace); + } + + public bool Equals(UsingInfo x, UsingInfo y) + { + return Compare(x, y) == 0; + } + + public int GetHashCode(UsingInfo obj) + { + return StringComparer.Ordinal.GetHashCode(obj.Namespace); + } + } + } +} diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.GenerateGlobalUsings.targets b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.GenerateGlobalUsings.targets new file mode 100644 index 000000000000..014d8d801a14 --- /dev/null +++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.GenerateGlobalUsings.targets @@ -0,0 +1,57 @@ + + + + + + + $(IntermediateOutputPath)$(MSBuildProjectName).GlobalUsings.g$(DefaultLanguageSourceExtension) + + + + + + + + + + + + + + + + + + diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.GenerateImplicitNamespaceImports.targets b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.GenerateImplicitNamespaceImports.targets deleted file mode 100644 index 661e992bb1fb..000000000000 --- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.GenerateImplicitNamespaceImports.targets +++ /dev/null @@ -1,57 +0,0 @@ - - - - - $(IntermediateOutputPath)$(MSBuildProjectName).ImplicitNamespaceImports$(DefaultLanguageSourceExtension) - false - - - - - - - - <_UniqueImport Include="@(Import->Distinct())" /> - <_ImportFileLine Include="// %3Cautogenerated />"/> - <_ImportFileLine Include="global using global::%(_UniqueImport.Identity)%3B"/> - - - - - - - - - - - diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.CSharp.props b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.CSharp.props index e327ce76fd0b..0425709fd7ea 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.CSharp.props +++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.CSharp.props @@ -23,4 +23,15 @@ Copyright (c) .NET Foundation. All rights reserved. $(DefineConstants)TRACE + + + + + + + + + + + diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.props b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.props index ceb02b0ff611..2495fed1f71c 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.props +++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.props @@ -82,49 +82,4 @@ Copyright (c) .NET Foundation. All rights reserved. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.VisualBasic.targets b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.VisualBasic.targets index b11585e617f7..79b21d6ecbde 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.VisualBasic.targets +++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.VisualBasic.targets @@ -10,6 +10,30 @@ Copyright (c) .NET Foundation. All rights reserved. *********************************************************************************************** --> + + + + + + + + + + + + + + + + + + + + + + + + $(Configuration.ToUpperInvariant()) diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.targets b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.targets index b4166a969f8d..b33bf5844890 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.targets +++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.targets @@ -39,7 +39,6 @@ Copyright (c) .NET Foundation. All rights reserved. true <_GenerateRuntimeConfigurationPropertyInputsCache Condition="'$(_GenerateRuntimeConfigurationPropertyInputsCache)' == ''">$(IntermediateOutputPath)$(MSBuildProjectName).genruntimeconfig.cache <_GenerateRuntimeConfigurationPropertyInputsCache>$([MSBuild]::NormalizePath($(MSBuildProjectDirectory), $(_GenerateRuntimeConfigurationPropertyInputsCache))) - $(DisableImplicitFrameworkReferences) @@ -1129,7 +1128,7 @@ Copyright (c) .NET Foundation. All rights reserved. - + diff --git a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildASelfContainedApp.cs b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildASelfContainedApp.cs index 6c3b79c9e04c..6de57bdb6b43 100644 --- a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildASelfContainedApp.cs +++ b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildASelfContainedApp.cs @@ -9,6 +9,8 @@ using Microsoft.NET.TestFramework.Assertions; using Microsoft.NET.TestFramework.Commands; using Microsoft.NET.TestFramework.ProjectConstruction; +using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Xml.Linq; @@ -276,7 +278,7 @@ static int Last2DigitsTo0(int versionBuild) RuntimePackNamePatterns='Microsoft.NETCore.App.Test.RuntimePack' RuntimePackRuntimeIdentifiers='any' /> - + "); project.Root.Add(itemGroup); diff --git a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateImplicitNamespaceImports_BlazorWasm.cs b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateGlobalUsings_BlazorWasm.cs similarity index 69% rename from src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateImplicitNamespaceImports_BlazorWasm.cs rename to src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateGlobalUsings_BlazorWasm.cs index 91629aeceb75..813126d8855d 100644 --- a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateImplicitNamespaceImports_BlazorWasm.cs +++ b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateGlobalUsings_BlazorWasm.cs @@ -12,17 +12,18 @@ namespace Microsoft.NET.Build.Tests { - public class GivenThatWeWantToGenerateImplicitNamespaceImports_BlazorWasm : SdkTest + public class GivenThatWeWantToGenerateGlobalUsings_BlazorWasm : SdkTest { - public GivenThatWeWantToGenerateImplicitNamespaceImports_BlazorWasm(ITestOutputHelper log) : base(log) { } + public GivenThatWeWantToGenerateGlobalUsings_BlazorWasm(ITestOutputHelper log) : base(log) { } [RequiresMSBuildVersionFact("17.0.0.32901")] - public void It_generates_blazorwasm_imports_and_builds_successfully() + public void It_generates_blazorwasm_usings_and_builds_successfully() { var tfm = "net6.0"; var testProject = CreateTestProject(tfm); + testProject.AdditionalProperties["ImplicitUsings"] = "enable"; var testAsset = _testAssetsManager.CreateTestProject(testProject); - var importFileName = $"{testAsset.TestProject.Name}.ImplicitNamespaceImports.cs"; + var globalUsingsFileName = $"{testAsset.TestProject.Name}.GlobalUsings.g.cs"; var buildCommand = new BuildCommand(testAsset); buildCommand @@ -32,10 +33,13 @@ public void It_generates_blazorwasm_imports_and_builds_successfully() var outputDirectory = buildCommand.GetIntermediateDirectory(tfm); - outputDirectory.Should().HaveFile(importFileName); + outputDirectory.Should().HaveFile(globalUsingsFileName); - File.ReadAllText(Path.Combine(outputDirectory.FullName, importFileName)).Should().Be( -@"// + File.ReadAllText(Path.Combine(outputDirectory.FullName, globalUsingsFileName)).Should().Be( +@"// +global using global::Microsoft.Extensions.Configuration; +global using global::Microsoft.Extensions.DependencyInjection; +global using global::Microsoft.Extensions.Logging; global using global::System; global using global::System.Collections.Generic; global using global::System.IO; @@ -43,20 +47,17 @@ public void It_generates_blazorwasm_imports_and_builds_successfully() global using global::System.Net.Http; global using global::System.Threading; global using global::System.Threading.Tasks; -global using global::Microsoft.Extensions.Configuration; -global using global::Microsoft.Extensions.DependencyInjection; -global using global::Microsoft.Extensions.Logging; "); } [Fact] - public void It_can_disable_blazorwasm_imports() + public void It_can_disable_blazorwasm_usings() { var tfm = "net6.0"; var testProject = CreateTestProject(tfm); - testProject.AdditionalProperties["DisableImplicitNamespaceImports_BlazorWasm"] = "true"; + testProject.AdditionalProperties["ImplicitUsings"] = "disable"; var testAsset = _testAssetsManager.CreateTestProject(testProject); - var importFileName = $"{testAsset.TestProject.Name}.ImplicitNamespaceImports.cs"; + var globalUsingsFileName = $"{testAsset.TestProject.Name}.GlobalUsings.g.cs"; var buildCommand = new BuildCommand(testAsset); buildCommand @@ -66,18 +67,7 @@ public void It_can_disable_blazorwasm_imports() var outputDirectory = buildCommand.GetIntermediateDirectory(tfm); - outputDirectory.Should().HaveFile(importFileName); - - File.ReadAllText(Path.Combine(outputDirectory.FullName, importFileName)).Should().Be( -@"// -global using global::System; -global using global::System.Collections.Generic; -global using global::System.IO; -global using global::System.Linq; -global using global::System.Net.Http; -global using global::System.Threading; -global using global::System.Threading.Tasks; -"); + outputDirectory.Should().NotHaveFile(globalUsingsFileName); } private TestProject CreateTestProject(string tfm) diff --git a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateImplicitNamespaceImports_DotNet.cs b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateGlobalUsings_DotNet.cs similarity index 55% rename from src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateImplicitNamespaceImports_DotNet.cs rename to src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateGlobalUsings_DotNet.cs index 8e8441d4881a..e58ddf9fcd38 100644 --- a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateImplicitNamespaceImports_DotNet.cs +++ b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateGlobalUsings_DotNet.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; +using System.Xml.Linq; using FluentAssertions; using Microsoft.NET.TestFramework; using Microsoft.NET.TestFramework.Assertions; @@ -13,17 +14,18 @@ namespace Microsoft.NET.Build.Tests { - public class GivenThatWeWantToGenerateImplicitNamespaceImports_DotNet : SdkTest + public class GivenThatWeWantToGenerateImpliciUsings_DotNet : SdkTest { - public GivenThatWeWantToGenerateImplicitNamespaceImports_DotNet(ITestOutputHelper log) : base(log) { } + public GivenThatWeWantToGenerateImpliciUsings_DotNet(ITestOutputHelper log) : base(log) { } [RequiresMSBuildVersionFact("17.0.0.32901")] - public void It_generates_dotnet_imports_and_builds_successfully() + public void It_can_generate_global_usings_and_builds_successfully() { var tfm = "net6.0"; var testProject = CreateTestProject(tfm); + testProject.AdditionalProperties["ImplicitUsings"] = "enable"; var testAsset = _testAssetsManager.CreateTestProject(testProject); - var importFileName = $"{testAsset.TestProject.Name}.ImplicitNamespaceImports.cs"; + var globalUsingsFileName = $"{testAsset.TestProject.Name}.GlobalUsings.g.cs"; var buildCommand = new BuildCommand(testAsset); buildCommand @@ -33,10 +35,10 @@ public void It_generates_dotnet_imports_and_builds_successfully() var outputDirectory = buildCommand.GetIntermediateDirectory(tfm); - outputDirectory.Should().HaveFile(importFileName); + outputDirectory.Should().HaveFile(globalUsingsFileName); - File.ReadAllText(Path.Combine(outputDirectory.FullName, importFileName)).Should().Be( -@"// + File.ReadAllText(Path.Combine(outputDirectory.FullName, globalUsingsFileName)).Should().Be( +@"// global using global::System; global using global::System.Collections.Generic; global using global::System.IO; @@ -48,13 +50,12 @@ public void It_generates_dotnet_imports_and_builds_successfully() } [Fact] - public void It_can_disable_dotnet_imports() + public void Implicit_Usings_Are_Not_Enabled_By_Default() { var tfm = "net6.0"; var testProject = CreateTestProject(tfm); - testProject.AdditionalProperties["DisableImplicitNamespaceImports_DotNet"] = "true"; var testAsset = _testAssetsManager.CreateTestProject(testProject); - var importFileName = $"{testAsset.TestProject.Name}.ImplicitNamespaceImports.cs"; + var globalUsingsFileName = $"{testAsset.TestProject.Name}.GlobalUsings.g.cs"; var buildCommand = new BuildCommand(testAsset); buildCommand @@ -64,17 +65,18 @@ public void It_can_disable_dotnet_imports() var outputDirectory = buildCommand.GetIntermediateDirectory(tfm); - outputDirectory.Should().NotHaveFile(importFileName); + outputDirectory.Should().NotHaveFile(globalUsingsFileName); } [RequiresMSBuildVersionFact("17.0.0.32901")] - public void It_can_remove_specific_imports_in_project_file() + public void It_can_remove_specific_usings_in_project_file() { var tfm = "net6.0"; var testProject = CreateTestProject(tfm); - testProject.AddItem("Import", "Remove", "System.IO"); + testProject.AdditionalProperties["ImplicitUsings"] = "enable"; + testProject.AddItem("Using", new Dictionary { ["Remove"] = "System.IO" }); var testAsset = _testAssetsManager.CreateTestProject(testProject); - var importFileName = $"{testAsset.TestProject.Name}.ImplicitNamespaceImports.cs"; + var globalUsingsFileName = $"{testAsset.TestProject.Name}.GlobalUsings.g.cs"; var buildCommand = new BuildCommand(testAsset); @@ -85,10 +87,10 @@ public void It_can_remove_specific_imports_in_project_file() var outputDirectory = buildCommand.GetIntermediateDirectory(tfm); - outputDirectory.Should().HaveFile(importFileName); + outputDirectory.Should().HaveFile(globalUsingsFileName); - File.ReadAllText(Path.Combine(outputDirectory.FullName, importFileName)).Should().Be( -@"// + File.ReadAllText(Path.Combine(outputDirectory.FullName, globalUsingsFileName)).Should().Be( +@"// global using global::System; global using global::System.Collections.Generic; global using global::System.Linq; @@ -99,14 +101,24 @@ public void It_can_remove_specific_imports_in_project_file() } [Fact] - public void It_can_generate_custom_imports() + public void It_can_generate_custom_usings() { var tfm = "net6.0"; var testProject = CreateTestProject(tfm); - testProject.AdditionalProperties["DisableImplicitNamespaceImports_DotNet"] = "true"; - testProject.AddItem("Import", "Include", "CustomNamespace"); + testProject.ProjectChanges.Add(projectXml => + { + var ns = projectXml.Root.Name.Namespace; + var itemGroup = new XElement(ns + "ItemGroup"); + projectXml.Root.Add(XElement.Parse( +@" + + + +")); + }); + var testAsset = _testAssetsManager.CreateTestProject(testProject); - var importFileName = $"{testAsset.TestProject.Name}.ImplicitNamespaceImports.cs"; + var globalUsingsFileName = $"{testAsset.TestProject.Name}.GlobalUsings.g.cs"; var buildCommand = new BuildCommand(testAsset); buildCommand @@ -116,23 +128,40 @@ public void It_can_generate_custom_imports() var outputDirectory = buildCommand.GetIntermediateDirectory(tfm); - outputDirectory.Should().HaveFile(importFileName); + outputDirectory.Should().HaveFile(globalUsingsFileName); - File.ReadAllText(Path.Combine(outputDirectory.FullName, importFileName)).Should().Be( -@"// + File.ReadAllText(Path.Combine(outputDirectory.FullName, globalUsingsFileName)).Should().Be( +@"// global using global::CustomNamespace; +global using AppliedChemistry = global::System.Biology; +global using static global::TestStaticNamespace; "); } [Fact] - public void It_ignores_duplicate_imports() + public void It_considers_switches_when_deduping() { var tfm = "net6.0"; var testProject = CreateTestProject(tfm); - testProject.AdditionalProperties["DisableImplicitNamespaceImports_DotNet"] = "true"; - testProject.AddItem("Import", "Include", "CustomNamespace;CustomNamespace"); + testProject.ProjectChanges.Add(projectXml => + { + var ns = projectXml.Root.Name.Namespace; + var itemGroup = new XElement(ns + "ItemGroup"); + projectXml.Root.Add(XElement.Parse( +@" + + + + + + + + +")); + }); + var testAsset = _testAssetsManager.CreateTestProject(testProject); - var importFileName = $"{testAsset.TestProject.Name}.ImplicitNamespaceImports.cs"; + var globalUsingsFileName = $"{testAsset.TestProject.Name}.GlobalUsings.g.cs"; var buildCommand = new BuildCommand(testAsset); buildCommand @@ -142,53 +171,18 @@ public void It_ignores_duplicate_imports() var outputDirectory = buildCommand.GetIntermediateDirectory(tfm); - outputDirectory.Should().HaveFile(importFileName); + outputDirectory.Should().HaveFile(globalUsingsFileName); - File.ReadAllText(Path.Combine(outputDirectory.FullName, importFileName)).Should().Be( -@"// + File.ReadAllText(Path.Combine(outputDirectory.FullName, globalUsingsFileName)).Should().Be( +@"// global using global::CustomNamespace; +global using global::TestStaticNamespace; +global using Disk = global::System.IO.File; +global using FileIO = global::System.IO.File; +global using static global::TestStaticNamespace; "); } - [Fact] - public void It_can_disable_import_generation() - { - var tfm = "net6.0"; - var testProject = CreateTestProject(tfm); - testProject.AdditionalProperties["DisableImplicitNamespaceImports"] = "true"; - var testAsset = _testAssetsManager.CreateTestProject(testProject); - var importFileName = $"{testAsset.TestProject.Name}.ImplicitNamespaceImports.cs"; - - var buildCommand = new BuildCommand(testAsset); - buildCommand - .Execute() - .Should() - .Fail(); - - var outputDirectory = buildCommand.GetIntermediateDirectory(tfm); - - outputDirectory.Should().NotHaveFile(importFileName); - } - - [Fact] - public void It_ignores_invalid_tfms() - { - var tfm = "net5.0"; - var testProject = CreateTestProject(tfm); - var testAsset = _testAssetsManager.CreateTestProject(testProject); - var importFileName = $"{testAsset.TestProject.Name}.ImplicitNamespaceImports.cs"; - - var buildCommand = new BuildCommand(testAsset); - buildCommand - .Execute() - .Should() - .Fail(); - - var outputDirectory = buildCommand.GetIntermediateDirectory(tfm); - - outputDirectory.Should().NotHaveFile(importFileName); - } - private TestProject CreateTestProject(string tfm) { var testProject = new TestProject diff --git a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateImplicitNamespaceImports_WebApp.cs b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateGlobalUsings_WebApp.cs similarity index 70% rename from src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateImplicitNamespaceImports_WebApp.cs rename to src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateGlobalUsings_WebApp.cs index a33c9c488151..082aa555b3d9 100644 --- a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateImplicitNamespaceImports_WebApp.cs +++ b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateGlobalUsings_WebApp.cs @@ -12,18 +12,19 @@ namespace Microsoft.NET.Build.Tests { - public class GivenThatWeWantToGenerateImplicitNamespaceImports_WebApp : SdkTest + public class GivenThatWeWantToGenerateGlobalUsings_WebApp : SdkTest { - public GivenThatWeWantToGenerateImplicitNamespaceImports_WebApp(ITestOutputHelper log) : base(log) { } + public GivenThatWeWantToGenerateGlobalUsings_WebApp(ITestOutputHelper log) : base(log) { } [RequiresMSBuildVersionFact("17.0.0.32901")] - public void It_generates_web_imports_and_builds_successfully() + public void It_generates_web_implicit_usings_and_builds_successfully() { var tfm = "net6.0"; var testProject = CreateTestProject(tfm); + testProject.AdditionalProperties["ImplicitUsings"] = "enable"; var testAsset = _testAssetsManager.CreateTestProject(testProject); - var importFileName = $"{testAsset.TestProject.Name}.ImplicitNamespaceImports.cs"; + var globalUsingsFileName = $"{testAsset.TestProject.Name}.GlobalUsings.g.cs"; var buildCommand = new BuildCommand(testAsset); buildCommand @@ -33,19 +34,10 @@ public void It_generates_web_imports_and_builds_successfully() var outputDirectory = buildCommand.GetIntermediateDirectory(tfm); + outputDirectory.Should().HaveFile(globalUsingsFileName); - outputDirectory.Should().HaveFile(importFileName); - - File.ReadAllText(Path.Combine(outputDirectory.FullName, importFileName)).Should().Be( -@"// -global using global::System; -global using global::System.Collections.Generic; -global using global::System.IO; -global using global::System.Linq; -global using global::System.Net.Http; -global using global::System.Threading; -global using global::System.Threading.Tasks; -global using global::System.Net.Http.Json; + File.ReadAllText(Path.Combine(outputDirectory.FullName, globalUsingsFileName)).Should().Be( +@"// global using global::Microsoft.AspNetCore.Builder; global using global::Microsoft.AspNetCore.Hosting; global using global::Microsoft.AspNetCore.Http; @@ -54,17 +46,25 @@ public void It_generates_web_imports_and_builds_successfully() global using global::Microsoft.Extensions.DependencyInjection; global using global::Microsoft.Extensions.Hosting; global using global::Microsoft.Extensions.Logging; +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Net.Http.Json; +global using global::System.Threading; +global using global::System.Threading.Tasks; "); } [Fact] - public void It_can_disable_web_imports() + public void It_can_disable_web_usings() { var tfm = "net6.0"; var testProject = CreateTestProject(tfm); - testProject.AdditionalProperties["DisableImplicitNamespaceImports_Web"] = "true"; + testProject.AdditionalProperties["ImplicitUsings"] = "disable"; var testAsset = _testAssetsManager.CreateTestProject(testProject); - var importFileName = $"{testAsset.TestProject.Name}.ImplicitNamespaceImports.cs"; + var globalUsingsFileName = $"{testAsset.TestProject.Name}.GlobalUsings.g.cs"; var buildCommand = new BuildCommand(testAsset); buildCommand @@ -74,18 +74,7 @@ public void It_can_disable_web_imports() var outputDirectory = buildCommand.GetIntermediateDirectory(tfm); - outputDirectory.Should().HaveFile(importFileName); - - File.ReadAllText(Path.Combine(outputDirectory.FullName, importFileName)).Should().Be( -@"// -global using global::System; -global using global::System.Collections.Generic; -global using global::System.IO; -global using global::System.Linq; -global using global::System.Net.Http; -global using global::System.Threading; -global using global::System.Threading.Tasks; -"); + outputDirectory.Should().NotHaveFile(globalUsingsFileName); } private TestProject CreateTestProject(string tfm) diff --git a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateImplicitNamespaceImports_Worker.cs b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateGlobalUsings_Worker.cs similarity index 76% rename from src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateImplicitNamespaceImports_Worker.cs rename to src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateGlobalUsings_Worker.cs index 76e06db55551..186bf1ed24a6 100644 --- a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateImplicitNamespaceImports_Worker.cs +++ b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToGenerateGlobalUsings_Worker.cs @@ -13,17 +13,18 @@ namespace Microsoft.NET.Build.Tests { - public class GivenThatWeWantToGenerateImplicitNamespaceImports_Worker : SdkTest + public class GivenThatWeWantToGenerateGlobalUsings_Worker : SdkTest { - public GivenThatWeWantToGenerateImplicitNamespaceImports_Worker(ITestOutputHelper log) : base(log) { } + public GivenThatWeWantToGenerateGlobalUsings_Worker(ITestOutputHelper log) : base(log) { } [RequiresMSBuildVersionFact("17.0.0.32901")] - public void It_generates_worker_imports_and_builds_successfully() + public void It_generates_worker_implicit_usings_and_builds_successfully() { var tfm = "net6.0"; var testProject = CreateTestProject(tfm); + testProject.AdditionalProperties["ImplicitUsings"] = "enable"; var testAsset = _testAssetsManager.CreateTestProject(testProject); - var importFileName = $"{testAsset.TestProject.Name}.ImplicitNamespaceImports.cs"; + var globalUsingsFileName = $"{testAsset.TestProject.Name}.GlobalUsings.g.cs"; var buildCommand = new BuildCommand(testAsset); buildCommand @@ -33,10 +34,14 @@ public void It_generates_worker_imports_and_builds_successfully() var outputDirectory = buildCommand.GetIntermediateDirectory(tfm); - outputDirectory.Should().HaveFile(importFileName); + outputDirectory.Should().HaveFile(globalUsingsFileName); - File.ReadAllText(Path.Combine(outputDirectory.FullName, importFileName)).Should().Be( -@"// + File.ReadAllText(Path.Combine(outputDirectory.FullName, globalUsingsFileName)).Should().Be( +@"// +global using global::Microsoft.Extensions.Configuration; +global using global::Microsoft.Extensions.DependencyInjection; +global using global::Microsoft.Extensions.Hosting; +global using global::Microsoft.Extensions.Logging; global using global::System; global using global::System.Collections.Generic; global using global::System.IO; @@ -44,21 +49,17 @@ public void It_generates_worker_imports_and_builds_successfully() global using global::System.Net.Http; global using global::System.Threading; global using global::System.Threading.Tasks; -global using global::Microsoft.Extensions.Configuration; -global using global::Microsoft.Extensions.DependencyInjection; -global using global::Microsoft.Extensions.Hosting; -global using global::Microsoft.Extensions.Logging; "); } [Fact] - public void It_can_disable_worker_imports() + public void It_can_disable_worker_usings() { var tfm = "net6.0"; var testProject = CreateTestProject(tfm); - testProject.AdditionalProperties["DisableImplicitNamespaceImports_Worker"] = "true"; + testProject.AdditionalProperties["ImplicitUsings"] = "disable"; var testAsset = _testAssetsManager.CreateTestProject(testProject); - var importFileName = $"{testAsset.TestProject.Name}.ImplicitNamespaceImports.cs"; + var globalUsingsFileName = $"{testAsset.TestProject.Name}.GlobalUsings.g..cs"; var buildCommand = new BuildCommand(testAsset); buildCommand @@ -68,18 +69,7 @@ public void It_can_disable_worker_imports() var outputDirectory = buildCommand.GetIntermediateDirectory(tfm); - outputDirectory.Should().HaveFile(importFileName); - - File.ReadAllText(Path.Combine(outputDirectory.FullName, importFileName)).Should().Be( -@"// -global using global::System; -global using global::System.Collections.Generic; -global using global::System.IO; -global using global::System.Linq; -global using global::System.Net.Http; -global using global::System.Threading; -global using global::System.Threading.Tasks; -"); + outputDirectory.Should().NotHaveFile(globalUsingsFileName); } private TestProject CreateTestProject(string tfm) diff --git a/src/Tests/dotnet-run.Tests/GivenDotnetRunRunsCsProj.cs b/src/Tests/dotnet-run.Tests/GivenDotnetRunRunsCsProj.cs index 43b1e084dcc6..1c863ee49630 100644 --- a/src/Tests/dotnet-run.Tests/GivenDotnetRunRunsCsProj.cs +++ b/src/Tests/dotnet-run.Tests/GivenDotnetRunRunsCsProj.cs @@ -247,6 +247,7 @@ public void ItRunsAppWhenRestoringToSpecificPackageDirectory() new DotnetCommand(Log, "run") .WithWorkingDirectory(rootPath) + .WithEnvironmentVariable("ImplicitUsings", "enable") // Removing tracked as part of https://github.com/dotnet/sdk/issues/19696 .Execute("--no-restore") .Should().Pass() .And.HaveStdOutContaining("Hello, World"); diff --git a/src/Tests/dotnet-workload-list.Tests/GivenDotnetWorkloadList.cs b/src/Tests/dotnet-workload-list.Tests/GivenDotnetWorkloadList.cs index bae8b79e21cc..40c58a5efbee 100644 --- a/src/Tests/dotnet-workload-list.Tests/GivenDotnetWorkloadList.cs +++ b/src/Tests/dotnet-workload-list.Tests/GivenDotnetWorkloadList.cs @@ -13,6 +13,7 @@ using Microsoft.NET.Sdk.WorkloadManifestReader; using ManifestReaderTests; using System.IO; +using System.Linq; namespace Microsoft.DotNet.Cli.Workload.List.Tests { diff --git a/src/Tests/dotnet.Tests/GivenThatICareAboutVBApps.cs b/src/Tests/dotnet.Tests/GivenThatICareAboutVBApps.cs index c2eb11355b0f..384f4259794e 100644 --- a/src/Tests/dotnet.Tests/GivenThatICareAboutVBApps.cs +++ b/src/Tests/dotnet.Tests/GivenThatICareAboutVBApps.cs @@ -2,13 +2,12 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information.  using System; -using System.Collections.Generic; using System.IO; using FluentAssertions; +using Microsoft.DotNet.Tools.Test.Utilities; using Microsoft.NET.TestFramework; using Microsoft.NET.TestFramework.Assertions; using Microsoft.NET.TestFramework.Commands; -using Microsoft.NET.TestFramework.ProjectConstruction; using Xunit; using Xunit.Abstractions; @@ -20,29 +19,6 @@ public GivenThatICareAboutVBApps(ITestOutputHelper log) : base(log) { } - [Fact] - public void ICanRemoveSpecificImportsInProjectFile() - { - var testProject = new TestProject - { - IsExe = true, - TargetFrameworks = "netcoreapp3.0", - ProjectSdk = "Microsoft.NET.Sdk" - }; - testProject.SourceFiles["Program.vb"] = @" -Module Program - Sub Main(args As String()) - Console.WriteLine(""Hello World!"") - End Sub -End Module -"; - testProject.AddItem("Import", "Remove", "System"); - var testInstance = _testAssetsManager.CreateTestProject(testProject); - - new BuildCommand(testInstance) - .Execute() - .Should().Fail(); - } [Fact] public void ICanBuildVBApps() diff --git a/src/WebSdk/Web/Sdk/Sdk.props b/src/WebSdk/Web/Sdk/Sdk.props index daba9686b6ec..3285d28e029b 100644 --- a/src/WebSdk/Web/Sdk/Sdk.props +++ b/src/WebSdk/Web/Sdk/Sdk.props @@ -58,18 +58,16 @@ Copyright (c) .NET Foundation. All rights reserved. IsImplicitlyDefined="true" /> - - - - - - - - - - + + + + + + + + + + diff --git a/src/WebSdk/Web/Sdk/Sdk.targets b/src/WebSdk/Web/Sdk/Sdk.targets index d1cee3c9fa9d..71fd818040e9 100644 --- a/src/WebSdk/Web/Sdk/Sdk.targets +++ b/src/WebSdk/Web/Sdk/Sdk.targets @@ -22,7 +22,6 @@ Copyright (c) .NET Foundation. All rights reserved. Microsoft.AspNetCore.App. This needs to happen after the .NET SDK has evaluated TFMs. --> true - false diff --git a/src/WebSdk/Worker/Targets/Microsoft.NET.Sdk.Worker.props b/src/WebSdk/Worker/Targets/Microsoft.NET.Sdk.Worker.props index 4fb1d8048d0e..cffa488585ca 100644 --- a/src/WebSdk/Worker/Targets/Microsoft.NET.Sdk.Worker.props +++ b/src/WebSdk/Worker/Targets/Microsoft.NET.Sdk.Worker.props @@ -38,13 +38,11 @@ Copyright (c) .NET Foundation. All rights reserved. <_ContentIncludedByDefault Include="@(Content)" /> - - - - - + + + + + diff --git a/src/WebSdk/Worker/Targets/Microsoft.NET.Sdk.Worker.targets b/src/WebSdk/Worker/Targets/Microsoft.NET.Sdk.Worker.targets index fa431d9289b6..8816f8d7b1d8 100644 --- a/src/WebSdk/Worker/Targets/Microsoft.NET.Sdk.Worker.targets +++ b/src/WebSdk/Worker/Targets/Microsoft.NET.Sdk.Worker.targets @@ -14,7 +14,6 @@ Copyright (c) .NET Foundation. All rights reserved. true $(MSBuildProjectDirectory) - false