Skip to content

Commit f2cc77b

Browse files
authored
Update implicit global usings feature (#19599)
* 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. Contributes to #19521
1 parent 4cc5526 commit f2cc77b

23 files changed

+362
-321
lines changed

src/BlazorWasmSdk/Sdk/Sdk.props

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,9 @@ Copyright (c) .NET Foundation. All rights reserved.
2020

2121
<Import Project="$(_BlazorWebAssemblyPropsFile)" />
2222

23-
<ItemGroup Condition=" '$(DisableImplicitNamespaceImports_BlazorWasm)' != 'true'
24-
And '$(TargetFrameworkIdentifier)' == '.NETCoreApp'
25-
And $([MSBuild]::VersionGreaterThanOrEquals('$(_TargetFrameworkVersionWithoutV)', '6.0'))">
26-
<Import Include="Microsoft.Extensions.Configuration" />
27-
<Import Include="Microsoft.Extensions.DependencyInjection" />
28-
<Import Include="Microsoft.Extensions.Logging" />
23+
<ItemGroup Condition="'$(ImplicitUsings)' == 'true' or '$(ImplicitUsings)' == 'enable'">
24+
<Using Include="Microsoft.Extensions.Configuration" />
25+
<Using Include="Microsoft.Extensions.DependencyInjection" />
26+
<Using Include="Microsoft.Extensions.Logging" />
2927
</ItemGroup>
3028
</Project>

src/BlazorWasmSdk/Sdk/Sdk.targets

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ Copyright (c) .NET Foundation. All rights reserved.
1313

1414
<PropertyGroup>
1515
<_BlazorWebAssemblyTargetsFile Condition="'$(_BlazorWebAssemblyTargetsFile)' == ''">$(MSBuildThisFileDirectory)..\targets\Microsoft.NET.Sdk.BlazorWebAssembly.Current.targets</_BlazorWebAssemblyTargetsFile>
16-
<DisableImplicitNamespaceImports_BlazorWasm Condition="'$(DisableImplicitNamespaceImports_BlazorWasm)' == '' and '$(DisableImplicitNamespaceImports)' != 'true'">false</DisableImplicitNamespaceImports_BlazorWasm>
1716
</PropertyGroup>
1817

1918
<ItemGroup>
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using Microsoft.Build.Framework;
9+
10+
namespace Microsoft.NET.Build.Tasks
11+
{
12+
public sealed class GenerateGlobalUsings : TaskBase
13+
{
14+
[Required]
15+
public ITaskItem[] Usings { get; set; }
16+
17+
[Output]
18+
public string[] Lines { get; set; }
19+
20+
protected override void ExecuteCore()
21+
{
22+
if (Usings.Length == 0)
23+
{
24+
Lines = Array.Empty<string>();
25+
return;
26+
}
27+
28+
var usings = Usings.Select(UsingInfo.Read)
29+
.OrderBy(static k => k, UsingInfoComparer.Instance)
30+
.Distinct(UsingInfoComparer.Instance);
31+
32+
var lines = new string[Usings.Length + 1];
33+
lines[0] = "// <auto-generated/>";
34+
35+
var index = 1;
36+
var lineBuilder = new StringBuilder();
37+
foreach (var @using in usings)
38+
{
39+
lineBuilder.Clear();
40+
lineBuilder.Append("global using ");
41+
42+
if (@using.Static)
43+
{
44+
lineBuilder.Append("static ");
45+
}
46+
47+
if (!string.IsNullOrEmpty(@using.Alias))
48+
{
49+
lineBuilder.Append(@using.Alias)
50+
.Append(" = ");
51+
}
52+
53+
lineBuilder.Append("global::")
54+
.Append(@using.Namespace)
55+
.Append(';');
56+
57+
lines[index++] = lineBuilder.ToString();
58+
}
59+
60+
Lines = lines;
61+
}
62+
63+
private readonly struct UsingInfo
64+
{
65+
public static UsingInfo Read(ITaskItem taskItem)
66+
{
67+
return new UsingInfo(
68+
taskItem.ItemSpec,
69+
taskItem.GetBooleanMetadata("Static") == true,
70+
taskItem.GetMetadata("Alias"));
71+
}
72+
73+
private UsingInfo(string @namespace, bool @static, string alias)
74+
{
75+
Namespace = @namespace;
76+
Static = @static;
77+
Alias = alias;
78+
}
79+
80+
public string Namespace { get; }
81+
public bool Static { get; }
82+
public string Alias { get; }
83+
}
84+
85+
private sealed class UsingInfoComparer : IComparer<UsingInfo>, IEqualityComparer<UsingInfo>
86+
{
87+
public static readonly UsingInfoComparer Instance = new();
88+
89+
public int Compare(UsingInfo x, UsingInfo y)
90+
{
91+
var @static = x.Static.CompareTo(y.Static);
92+
if (@static != 0)
93+
{
94+
return @static;
95+
}
96+
97+
var alias = x.Alias.CompareTo(y.Alias);
98+
if (alias != 0)
99+
{
100+
return alias;
101+
}
102+
103+
return StringComparer.Ordinal.Compare(x.Namespace, y.Namespace);
104+
}
105+
106+
public bool Equals(UsingInfo x, UsingInfo y)
107+
{
108+
return Compare(x, y) == 0;
109+
}
110+
111+
public int GetHashCode(UsingInfo obj)
112+
{
113+
return StringComparer.Ordinal.GetHashCode(obj.Namespace);
114+
}
115+
}
116+
}
117+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<!--
2+
***********************************************************************************************
3+
Microsoft.NET.GenerateGlobalUsings.targets
4+
5+
WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
6+
created a backup copy. Incorrect changes to this file will make it
7+
impossible to load or build your projects from the command-line or the IDE.
8+
9+
Copyright (c) .NET Foundation. All rights reserved.
10+
***********************************************************************************************
11+
-->
12+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
13+
<!--
14+
============================================================
15+
GenerateGlobalUsings
16+
17+
Generates implicit namespace imports source to intermediate directory for C# projects
18+
============================================================
19+
-->
20+
<UsingTask TaskName="GenerateGlobalUsings" AssemblyFile="$(MicrosoftNETBuildTasksAssembly)" />
21+
22+
<PropertyGroup>
23+
<GeneratedGlobalUsingsFile Condition="'$(GeneratedGlobalUsingsFile)' ==''">$(IntermediateOutputPath)$(MSBuildProjectName).GlobalUsings.g$(DefaultLanguageSourceExtension)</GeneratedGlobalUsingsFile>
24+
</PropertyGroup>
25+
26+
<!--
27+
Note that this must run before every invocation of CoreCompile to ensure that all compiler
28+
runs see the generated global usings. There is at least one scenario involving Xaml
29+
where CoreCompile is invoked without other potential hooks such as Compile or CoreBuild,
30+
etc., so we hook directly on to CoreCompile. Furthermore, we must run *after*
31+
PrepareForBuild to ensure that the intermediate directory has been created.
32+
33+
Targets that generate Compile items are also expected to run before
34+
BeforeCompile targets (common targets convention).
35+
-->
36+
<Target Name="GenerateGlobalUsings"
37+
BeforeTargets="BeforeCompile;CoreCompile"
38+
AfterTargets="PrepareForBuild"
39+
Condition="@(Using->Count()) != 0">
40+
41+
<GenerateGlobalUsings Usings="@(Using)">
42+
<Output TaskParameter="Lines" ItemName="_GlobalUsingLines" />
43+
</GenerateGlobalUsings>
44+
45+
<WriteLinesToFile
46+
File="$(GeneratedGlobalUsingsFile)"
47+
Lines="@(_GlobalUsingLines)"
48+
Overwrite="true"
49+
WriteOnlyWhenDifferent="true" />
50+
51+
<ItemGroup>
52+
<Compile Include="$(GeneratedGlobalUsingsFile)" />
53+
<FileWrites Include="$(GeneratedGlobalUsingsFile)" />
54+
</ItemGroup>
55+
</Target>
56+
57+
</Project>

src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.GenerateImplicitNamespaceImports.targets

Lines changed: 0 additions & 57 deletions
This file was deleted.

src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.CSharp.props

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,15 @@ Copyright (c) .NET Foundation. All rights reserved.
2323
<DefineConstants>$(DefineConstants)TRACE</DefineConstants>
2424
</PropertyGroup>
2525

26+
<!-- Implicit imports -->
27+
<ItemGroup Condition="'$(ImplicitUsings)' == 'true' Or '$(ImplicitUsings)' == 'enable'">
28+
<Using Include="System" />
29+
<Using Include="System.Collections.Generic" />
30+
<Using Include="System.IO" />
31+
<Using Include="System.Linq" />
32+
<Using Include="System.Net.Http" />
33+
<Using Include="System.Threading" />
34+
<Using Include="System.Threading.Tasks" />
35+
</ItemGroup>
36+
2637
</Project>

src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.props

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -82,49 +82,4 @@ Copyright (c) .NET Foundation. All rights reserved.
8282

8383
</ItemGroup>
8484

85-
<!-- Implicit imports -->
86-
<ItemGroup Condition=" '$(DisableImplicitNamespaceImports_DotNet)' != 'true'
87-
and '$(TargetFrameworkIdentifier)' == '.NETCoreApp'
88-
and $([MSBuild]::VersionGreaterThanOrEquals($(_TargetFrameworkVersionWithoutV), '6.0'))">
89-
90-
<!-- Imports already defined as VB implicit imports are conditioned to not be added twice -->
91-
<Import Include="System" Condition="'$(Language)' != 'VB'" />
92-
<Import Include="System.Collections.Generic" Condition="'$(Language)' != 'VB'" />
93-
<Import Include="System.IO" />
94-
<Import Include="System.Linq" Condition="'$(Language)' != 'VB'" />
95-
<Import Include="System.Net.Http" />
96-
<Import Include="System.Threading" />
97-
<Import Include="System.Threading.Tasks" Condition="'$(Language)' != 'VB'" />
98-
99-
</ItemGroup>
100-
101-
<!-- VB implicit imports -->
102-
<ItemGroup Condition=" '$(DisableImplicitNamespaceImports)' != 'true'
103-
and '$(Language)' == 'VB'
104-
and '$(TargetFrameworkIdentifier)' == '.NETFramework'">
105-
<!-- These namespaces are present in 2.0 Framework assemblies -->
106-
<Import Include="Microsoft.VisualBasic" />
107-
<Import Include="System" />
108-
<Import Include="System.Collections" />
109-
<Import Include="System.Collections.Generic" />
110-
<Import Include="System.Data" />
111-
<Import Include="System.Diagnostics" />
112-
<!-- These namespaces are introduced in 3.5 Framework assemblies -->
113-
<Import Include="System.Linq" Condition="('$(_TargetFrameworkVersionWithoutV)' != '') And ('$(_TargetFrameworkVersionWithoutV)' >= '3.5')"/>
114-
<Import Include="System.Xml.Linq" Condition="('$(_TargetFrameworkVersionWithoutV)' != '') And ('$(_TargetFrameworkVersionWithoutV)' >= '3.5')"/>
115-
<!-- This namespace is introduced in 4.0 Framework assemblies -->
116-
<Import Include="System.Threading.Tasks" Condition="('$(_TargetFrameworkVersionWithoutV)' != '') And ('$(_TargetFrameworkVersionWithoutV)' >= '4.0')"/>
117-
</ItemGroup>
118-
<ItemGroup Condition=" '$(DisableImplicitNamespaceImports)' != 'true'
119-
and '$(Language)' == 'VB'
120-
and '$(_IsNETCoreOrNETStandard)' == 'true'">
121-
<Import Include="Microsoft.VisualBasic" />
122-
<Import Include="System" />
123-
<Import Include="System.Collections" />
124-
<Import Include="System.Collections.Generic" />
125-
<Import Include="System.Diagnostics" />
126-
<Import Include="System.Linq" />
127-
<Import Include="System.Xml.Linq" />
128-
<Import Include="System.Threading.Tasks" />
129-
</ItemGroup>
13085
</Project>

src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.VisualBasic.targets

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,30 @@ Copyright (c) .NET Foundation. All rights reserved.
1010
***********************************************************************************************
1111
-->
1212
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
13+
<ItemGroup Condition=" '$(DisableImplicitNamespaceImports)' != 'true' and '$(TargetFrameworkIdentifier)' == '.NETFramework'">
14+
<!-- These namespaces are present in 2.0 Framework assemblies -->
15+
<Import Include="Microsoft.VisualBasic" />
16+
<Import Include="System" />
17+
<Import Include="System.Collections" />
18+
<Import Include="System.Collections.Generic" />
19+
<Import Include="System.Data" />
20+
<Import Include="System.Diagnostics" />
21+
<!-- These namespaces are introduced in 3.5 Framework assemblies -->
22+
<Import Include="System.Linq" Condition=" '$(_TargetFrameworkVersionWithoutV)' >= '3.5' "/>
23+
<Import Include="System.Xml.Linq" Condition=" '$(_TargetFrameworkVersionWithoutV)' >= '3.5' "/>
24+
<!-- This namespace is introduced in 4.0 Framework assemblies -->
25+
<Import Include="System.Threading.Tasks" Condition=" '$(_TargetFrameworkVersionWithoutV)' >= '4.0' "/>
26+
</ItemGroup>
27+
<ItemGroup Condition=" '$(DisableImplicitNamespaceImports)' != 'true' and '$(_IsNETCoreOrNETStandard)' == 'true'">
28+
<Import Include="Microsoft.VisualBasic" />
29+
<Import Include="System" />
30+
<Import Include="System.Collections" />
31+
<Import Include="System.Collections.Generic" />
32+
<Import Include="System.Diagnostics" />
33+
<Import Include="System.Linq" />
34+
<Import Include="System.Xml.Linq" />
35+
<Import Include="System.Threading.Tasks" />
36+
</ItemGroup>
1337
<PropertyGroup Condition="'$(DisableImplicitConfigurationDefines)' != 'true' and '$(Configuration)' != ''">
1438
<ImplicitConfigurationDefine>$(Configuration.ToUpperInvariant())</ImplicitConfigurationDefine>
1539

src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.targets

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ Copyright (c) .NET Foundation. All rights reserved.
3939
<ComputeNETCoreBuildOutputFiles Condition=" '$(ComputeNETCoreBuildOutputFiles)' == '' and '$(TargetFrameworkIdentifier)' == '.NETCoreApp'">true</ComputeNETCoreBuildOutputFiles>
4040
<_GenerateRuntimeConfigurationPropertyInputsCache Condition="'$(_GenerateRuntimeConfigurationPropertyInputsCache)' == ''">$(IntermediateOutputPath)$(MSBuildProjectName).genruntimeconfig.cache</_GenerateRuntimeConfigurationPropertyInputsCache>
4141
<_GenerateRuntimeConfigurationPropertyInputsCache>$([MSBuild]::NormalizePath($(MSBuildProjectDirectory), $(_GenerateRuntimeConfigurationPropertyInputsCache)))</_GenerateRuntimeConfigurationPropertyInputsCache>
42-
<DisableImplicitNamespaceImports Condition="'$(DisableImplicitNamespaceImports)'==''">$(DisableImplicitFrameworkReferences)</DisableImplicitNamespaceImports>
4342
</PropertyGroup>
4443

4544
<ItemGroup>
@@ -1129,7 +1128,7 @@ Copyright (c) .NET Foundation. All rights reserved.
11291128
<Import Project="$(MSBuildThisFileDirectory)Microsoft.NET.DisableStandardFrameworkResolution.targets" Condition="'$(DisableStandardFrameworkResolution)' == 'true'" />
11301129
<Import Project="$(MSBuildThisFileDirectory)Microsoft.NET.DesignerSupport.targets" />
11311130
<Import Project="$(MSBuildThisFileDirectory)Microsoft.NET.GenerateAssemblyInfo.targets" Condition="'$(UsingNETSdkDefaults)' == 'true'"/>
1132-
<Import Project="$(MSBuildThisFileDirectory)Microsoft.NET.GenerateImplicitNamespaceImports.targets" Condition="'$(DisableImplicitNamespaceImports)' != 'true' and '$(Language)' == 'C#'"/>
1131+
<Import Project="$(MSBuildThisFileDirectory)Microsoft.NET.GenerateGlobalUsings.targets" Condition="'$(Language)' == 'C#'"/>
11331132
<Import Project="$(MSBuildThisFileDirectory)Microsoft.NET.GenerateSupportedRuntime.targets" />
11341133
<Import Project="$(MSBuildThisFileDirectory)Microsoft.NET.ComposeStore.targets" Condition="'$(UsingNETSdkDefaults)' == 'true'" />
11351134
<Import Project="$(MSBuildThisFileDirectory)Microsoft.NET.CrossGen.targets" />

src/Tests/EndToEnd.Tests/GivenDotNetUsesMSBuild.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public GivenDotNetUsesMSBuild(ITestOutputHelper log) : base(log)
2121
{
2222
}
2323

24-
[RequiresMSBuildVersionFact("17.0.0.32901")]
24+
[RequiresMSBuildVersionFact("17.0.0.32901", Skip = "Unskipping tracked by https://github.com/dotnet/sdk/issues/19696")]
2525
public void ItCanNewRestoreBuildRunCleanMSBuildProject()
2626
{
2727
string projectDirectory = _testAssetsManager.CreateTestDirectory().Path;

0 commit comments

Comments
 (0)