Associate C# version with each Razor extension version.

- Roslyn now default to 8.0 C# so it's no longer specified in a users project file. Because of this restriction we can no longer see the projects `LangVersion` when generating Razor files. Meaning, we can't conditionally generate C# 8.0 aware code because our Razor default is not C# 8.0. Therefore, when we detect that the C# lang version hasn't been provided we don't set a C# version and instead rely on what the default configuration for the Razor project is. In practice this looks like:
  - MVC1.X = C# 7.3
  - MVC2.X = C# 7.3
  - MVC Latest = C# 8.0
- I thought about adding a feature flags variant for `RazorCodeGenerationOptions` but decided not to since C# features are all configurable options that are based on more than just the `RazorLangVersion`.
- Added integration tests to ensure that command line builds with implicit `LangVersion`s result in proper C# nullability handling.

aspnet/AspNetCoredotnet/aspnetcore-tooling#12594
\n\nCommit migrated from f039aa9354
This commit is contained in:
N. Taylor Mullen 2019-08-02 09:35:57 -07:00
parent 6ad8b96f3e
commit e2d476cc6f
6 changed files with 61 additions and 17 deletions

View File

@ -4,6 +4,7 @@
using System;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Razor;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
@ -38,6 +39,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
builder.Features.Add(new MvcViewDocumentClassifierPass());
builder.Features.Add(new MvcImportProjectFeature());
// The default C# language version for what this Razor configuration supports.
builder.SetCSharpLanguageVersion(LanguageVersion.CSharp7_3);
}
public static void RegisterViewComponentTagHelpers(RazorProjectEngineBuilder builder)

View File

@ -4,6 +4,7 @@
using System;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Razor;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X
@ -44,6 +45,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X
builder.Features.Add(new InstrumentationPass());
builder.Features.Add(new MvcImportProjectFeature());
// The default C# language version for what this Razor configuration supports.
builder.SetCSharpLanguageVersion(LanguageVersion.CSharp7_3);
}
}
}

View File

@ -4,6 +4,7 @@
using System;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Razor;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
@ -39,6 +40,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
builder.Features.Add(new MvcViewDocumentClassifierPass());
builder.Features.Add(new MvcImportProjectFeature());
// The default C# language version for what this Razor configuration supports.
builder.SetCSharpLanguageVersion(LanguageVersion.CSharp8);
}
}
}

View File

@ -176,20 +176,6 @@ namespace Microsoft.AspNetCore.Razor.Tools
});
var success = true;
var csharpLanguageVersion = LanguageVersion.Default;
if (CSharpLanguageVersion.HasValue())
{
var rawLanguageVersion = CSharpLanguageVersion.Value();
if (!LanguageVersionFacts.TryParse(CSharpLanguageVersion.Value(), out var parsedLanguageVersion))
{
success = false;
Error.WriteLine($"Unknown C# language version {rawLanguageVersion}.");
}
else
{
csharpLanguageVersion = parsedLanguageVersion;
}
}
var engine = RazorProjectEngine.Create(configuration, compositeFileSystem, b =>
{
@ -206,7 +192,22 @@ namespace Microsoft.AspNetCore.Razor.Tools
b.SetRootNamespace(RootNamespace.Value());
}
b.SetCSharpLanguageVersion(csharpLanguageVersion);
if (CSharpLanguageVersion.HasValue())
{
// Only set the C# language version if one was specified, otherwise it defaults to whatever
// value was set in the corresponding RazorConfiguration's extensions.
var rawLanguageVersion = CSharpLanguageVersion.Value();
if (LanguageVersionFacts.TryParse(rawLanguageVersion, out var csharpLanguageVersion))
{
b.SetCSharpLanguageVersion(csharpLanguageVersion);
}
else
{
success = false;
Error.WriteLine($"Unknown C# language version {rawLanguageVersion}.");
}
}
});
var results = GenerateCode(engine, sourceItems);

View File

@ -60,7 +60,7 @@ namespace Microsoft.CodeAnalysis.Razor
throw new ArgumentNullException(nameof(options));
}
if (options.Configuration.LanguageVersion.Major < 3)
if (options.Configuration != null && options.Configuration.LanguageVersion.Major < 3)
{
// Prior to 3.0 there were no C# version specific controlled features. Suppress nullability enforcement.
options.SuppressNullabilityEnforcement = true;

View File

@ -641,7 +641,38 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
[Fact]
[InitializeTestProject("SimpleMvc")]
public async Task Build_CSharp8_NullableEnforcement_WarningsDuringBuild_BuildServer()
public async Task Build_ImplicitCSharp8_NullableEnforcement_WarningsDuringBuild_NoBuildServer()
{
var result = await DotnetMSBuild(
"Build",
"/p:Nullable=enable",
suppressBuildServer: true);
var indexFilePath = Path.Combine(RazorIntermediateOutputPath, "Views", "Home", "Index.cshtml.g.cs");
Assert.BuildPassed(result, allowWarnings: true);
Assert.BuildWarning(result, "CS8618");
Assert.FileContainsLine(result, indexFilePath, "#nullable restore");
Assert.FileContainsLine(result, indexFilePath, "#nullable disable");
}
[Fact]
[InitializeTestProject("SimpleMvc")]
public async Task Build_ExplicitCSharp73_NullableEnforcement_Disabled_NoNullableFeature_NoBuildServer()
{
var result = await DotnetMSBuild(
"Build",
"/p:LangVersion=7.3",
suppressBuildServer: true);
var indexFilePath = Path.Combine(RazorIntermediateOutputPath, "Views", "Home", "Index.cshtml.g.cs");
Assert.BuildPassed(result, allowWarnings: false);
Assert.FileDoesNotContainLine(result, indexFilePath, "#nullable restore");
Assert.FileDoesNotContainLine(result, indexFilePath, "#nullable disable");
}
[Fact]
[InitializeTestProject("SimpleMvc")]
public async Task Build_ExplicitCSharp8_NullableEnforcement_WarningsDuringBuild_BuildServer()
{
var result = await DotnetMSBuild(
"Build",