diff --git a/src/Razor/Directory.Build.props b/src/Razor/Directory.Build.props
index d43f1c13df7e8..1737c22d8657d 100644
--- a/src/Razor/Directory.Build.props
+++ b/src/Razor/Directory.Build.props
@@ -9,9 +9,6 @@
false
true
false
-
-
-
diff --git a/src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentRenderModeDirectiveIntegrationTests.cs b/src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentRenderModeDirectiveIntegrationTests.cs
index 698b9cf7e6f65..b5f429f5d8a66 100644
--- a/src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentRenderModeDirectiveIntegrationTests.cs
+++ b/src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentRenderModeDirectiveIntegrationTests.cs
@@ -56,7 +56,7 @@ @rendermode Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer
Diagnostic(ErrorCode.ERR_BadArity, "TestComponent").WithArguments("Test.TestComponent", "type", "1").WithLocation(13, 19));
}
- [Fact(Skip = "PROTOTYPE(sonic): rendermode lowering doesn't emit a #line directive on the synthesized attribute decoration in the decl half, so the resulting diagnostic points at the generated file instead of the @rendermode token. Track + fix before merging to main. See PR #83887.")]
+ [Fact]
public void RenderMode_GenericComponent_CSharp10()
{
var csharpParseOptions = CSharpParseOptions.WithLanguageVersion(CodeAnalysis.CSharp.LanguageVersion.CSharp10);
@@ -69,17 +69,16 @@ @rendermode Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer
""");
CompileToAssembly(compilationResult,
- // PROTOTYPE: this diagnostic should map back to the @rendermode directive in
- // the source rather than the synthesized attribute decoration in the decl
- // generated file. The decoration is added without a SourceSpan so the writer
- // emits it without a #line directive. Track + fix before merging to main.
+ // @rendermode on a generic (@typeparam) component generates an attribute decoration that
+ // references the component without its type argument, plus a nested attribute type that needs
+ // generic-attribute support. This is a known limitation
+ // (https://github.com/dotnet/razor/issues/9683): the file-scoped attribute class generated for
+ // C# 11+ avoids it, but C# 10 still surfaces the raw C# errors against the generated code.
//
- // x:\dir\subdir\Test\TestComponent.cshtml.decl.g.cs(13,19): error CS0305: Using the generic type 'TestComponent' requires 1 type arguments
- // [global::Test.TestComponent.__PrivateComponentRenderModeAttribute]
+ // x:\dir\subdir\Test\TestComponent.cshtml(13,19): error CS0305: Using the generic type 'TestComponent' requires 1 type arguments
Diagnostic(ErrorCode.ERR_BadArity, "TestComponent").WithArguments("Test.TestComponent", "type", "1").WithLocation(13, 19),
- // x:\dir\subdir\Test\TestComponent.cshtml(30,70): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater.
- // private sealed class __PrivateComponentRenderModeAttribute : global::Microsoft.AspNetCore.Components.RenderModeAttribute
- Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "global::Microsoft.AspNetCore.Components.RenderModeAttribute").WithArguments("generic attributes", "11.0").WithLocation(30, 70));
+ // x:\dir\subdir\Test\TestComponent.cshtml(31,70): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater.
+ Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "global::Microsoft.AspNetCore.Components.RenderModeAttribute").WithArguments("generic attributes", "11.0").WithLocation(31, 70));
}
[Fact]
@@ -238,7 +237,7 @@ @rendermode Foo
CompileToAssembly(compilationResult);
}
- [Fact(Skip = "PROTOTYPE(sonic): rendermode lowering doesn't emit a #line directive on the synthesized `=> ` arrow expression, so the diagnostic's line/column point inside the generated helper rather than at the user's @rendermode token. Track + fix before merging to main. See PR #83887.")]
+ [Fact]
public void LanguageVersion_BreakingChange_8_0()
{
var compilationResult = CompileToCSharp("""
@@ -253,15 +252,15 @@ @rendermode Foo
Assert.Empty(compilationResult.RazorDiagnostics);
CompileToAssembly(compilationResult,
- // PROTOTYPE: the rendermode lowering doesn't emit a #line directive on the
- // synthesized `=> ` arrow expression, so this diagnostic's line/column
- // point inside the generated helper rather than at the user's @rendermode
- // token. Pre-existing limitation but worth fixing -- track + address before
- // merging to main.
+ // On Razor < 11 the @rendermode expression isn't mapped back to source, so a diagnostic on the
+ // expression reports the generated line/column inside the synthesized ModeImpl helper rather
+ // than the @rendermode token. This can't be fixed retroactively for those language versions:
+ // changing the generated code now would make a newer compiler emit different output than the
+ // shipped VS tooling expects, which breaks hot reload. Mapping was only added for Razor 11+
+ // (dotnet/razor#12604).
//
- // x:\dir\subdir\Test\TestComponent.cshtml(24,101): error CS0103: The name 'Foo' does not exist in the current context
- // private static IComponentRenderMode ModeImpl => Foo;
- Diagnostic(ErrorCode.ERR_NameNotInContext, "Foo").WithArguments("Foo").WithLocation(24, 101),
+ // x:\dir\subdir\Test\TestComponent.cshtml(25,101): error CS0103: The name 'Foo' does not exist in the current context
+ Diagnostic(ErrorCode.ERR_NameNotInContext, "Foo").WithArguments("Foo").WithLocation(25, 101),
// x:\dir\subdir\Test\TestComponent.cshtml(5,12): warning CS0414: The field 'TestComponent.rendermode' is assigned but its value is never used
// string rendermode = "Something";
Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "rendermode").WithArguments("Test.TestComponent.rendermode").WithLocation(5, 12)
diff --git a/src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorCodeDocument.cs b/src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorCodeDocument.cs
index a07045af4979a..e6e0683698dec 100644
--- a/src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorCodeDocument.cs
+++ b/src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorCodeDocument.cs
@@ -284,27 +284,6 @@ internal RazorCodeDocument WithUnresolvedDocumentNode(DocumentIntermediateNode v
internal RazorCSharpDocument GetRequiredCSharpDocument(bool declarationDocument)
=> GetCSharpDocument(declarationDocument).AssumeNotNull();
-#if SONICDEV
- [System.Obsolete("PROTOTYPE(sonic): Call the overload that takes a bool to prove that you thought about which document to get")]
-#endif
- internal bool TryGetImplCSharpDocument([NotNullWhen(true)] out RazorCSharpDocument? result)
- {
- result = _csharpDocument;
- return result is not null;
- }
-
-#if SONICDEV
- [System.Obsolete("PROTOTYPE(sonic): Call the overload that takes a bool to prove that you thought about which document to get")]
-#endif
- internal RazorCSharpDocument? GetImplCSharpDocument()
- => _csharpDocument;
-
-#if SONICDEV
- [System.Obsolete("PROTOTYPE(sonic): Call the overload that takes a bool to prove that you thought about which document to get")]
-#endif
- internal RazorCSharpDocument GetRequiredImplCSharpDocument()
- => _csharpDocument.AssumeNotNull();
-
internal RazorCodeDocument WithImplCSharpDocument(RazorCSharpDocument value)
{
Debug.Assert(value is not null);
@@ -315,12 +294,6 @@ internal RazorCodeDocument WithImplCSharpDocument(RazorCSharpDocument value)
return new RazorCodeDocument(Source, Imports, ParserOptions, CodeGenerationOptions, _tagHelpers, _referencedTagHelpers, _syntaxTree, _tagHelperRewrittenSyntaxTree, _importSyntaxTrees, _tagHelperContext, _documentNode, value, _declCSharpDocument, _directiveTagHelperContributions, _unresolvedDocumentNode);
}
-#if SONICDEV
- [System.Obsolete("PROTOTYPE(sonic): Call the overload that takes a bool to prove that you thought about which document to get")]
-#endif
- internal RazorCSharpDocument? GetDeclCSharpDocument()
- => _declCSharpDocument;
-
internal RazorCodeDocument WithDeclCSharpDocument(RazorCSharpDocument value)
{
Debug.Assert(value is not null);
diff --git a/src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorSourceGenerator.cs b/src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorSourceGenerator.cs
index cf9b495691471..273ad807cf1bc 100644
--- a/src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorSourceGenerator.cs
+++ b/src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorSourceGenerator.cs
@@ -107,7 +107,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
{
RazorSourceGeneratorEventSource.Log.GenerateDeclarationCodeStart(sourceItem.FilePath);
var declEngine = GetDeclarationProjectEngine(sourceItem, imports, razorSourceGeneratorOptions);
- fallbackDecl = declEngine.Process(sourceItem, cancellationToken).GetRequiredImplCSharpDocument();
+ fallbackDecl = declEngine.Process(sourceItem, cancellationToken).GetRequiredCSharpDocument(declarationDocument: false);
fallbackTypeName = typeName;
RazorSourceGeneratorEventSource.Log.GenerateDeclarationCodeStop(sourceItem.FilePath);
}
@@ -129,7 +129,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
var declSources = processedDocuments
.Select(static (item, _) =>
{
- var declCSharpDocument = item.document.CodeDocument.GetDeclCSharpDocument();
+ var declCSharpDocument = item.document.CodeDocument.GetCSharpDocument(declarationDocument: true);
return (hintName: GetIdentifierFromPath(item.path), declCSharpDocument);
})
.Where(static item => item.declCSharpDocument is not null)
@@ -423,8 +423,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
return (
hintName: GetIdentifierFromPath(filePath),
codeDocument: document.CodeDocument,
- csharpDocument: document.CodeDocument.GetRequiredImplCSharpDocument(),
- declCSharpDocument: document.CodeDocument.GetDeclCSharpDocument());
+ csharpDocument: document.CodeDocument.GetRequiredCSharpDocument(declarationDocument: false),
+ declCSharpDocument: document.CodeDocument.GetCSharpDocument(declarationDocument: true));
})
.WithLambdaComparer(static (a, b) =>
{
diff --git a/src/Razor/src/Compiler/perf/Microbenchmarks/CodeGenerationBenchmark.cs b/src/Razor/src/Compiler/perf/Microbenchmarks/CodeGenerationBenchmark.cs
index 3151025b2e16c..a512440850193 100644
--- a/src/Razor/src/Compiler/perf/Microbenchmarks/CodeGenerationBenchmark.cs
+++ b/src/Razor/src/Compiler/perf/Microbenchmarks/CodeGenerationBenchmark.cs
@@ -37,7 +37,7 @@ public CodeGenerationBenchmark()
public void CodeGeneration_Runtime_LargeStaticFile()
{
var codeDocument = ProjectEngine.Process(MSN);
- var generated = codeDocument.GetRequiredImplCSharpDocument();
+ var generated = codeDocument.GetRequiredCSharpDocument(declarationDocument: false);
if (generated.Diagnostics.Length > 0)
{
diff --git a/src/Razor/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/ProjectExtensions.cs b/src/Razor/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/ProjectExtensions.cs
index 91cf6a09c83ee..48a09d1f2b446 100644
--- a/src/Razor/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/ProjectExtensions.cs
+++ b/src/Razor/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/ProjectExtensions.cs
@@ -37,14 +37,6 @@ internal static class ProjectExtensions
return generatedDocuments.SingleOrDefault(d => d.HintName == hintName);
}
-#if SONICDEV
- [System.Obsolete("PROTOTYPE(sonic): Call the overload that takes a bool to prove that you thought about which document to get")]
-#endif
- public static async Task TryGetSourceGeneratedDocumentForRazorDocumentAsync(this Project project, TextDocument razorDocument, CancellationToken cancellationToken)
- {
- return (await TryGetSourceGeneratedDocumentsForRazorDocumentAsync(project, razorDocument, cancellationToken).ConfigureAwait(false))?.ImplDoc;
- }
-
///
/// Finds source generated documents by iterating through all of them. In OOP there are better options!
///
diff --git a/src/Razor/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs b/src/Razor/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs
index 214e03541b85e..dc600488eeddc 100644
--- a/src/Razor/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs
+++ b/src/Razor/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs
@@ -29,12 +29,6 @@ public static bool TryGetSyntaxRoot(this RazorCodeDocument codeDocument, [NotNul
public static Syntax.SyntaxNode GetRequiredSyntaxRoot(this RazorCodeDocument codeDocument)
=> codeDocument.GetRequiredTagHelperRewrittenSyntaxTree().Root;
-#if SONICDEV
- [System.Obsolete("PROTOTYPE(sonic): Call GetRequiredCSharpDocument and use the Text property on that, to prove that you thought about which document to get")]
-#endif
- public static SourceText GetCSharpSourceText(this RazorCodeDocument document)
- => document.GetRequiredImplCSharpDocument().Text;
-
///
/// Returns the generated that corresponds to the given
/// generated-source hint name. For Razor components the generator can emit two halves:
diff --git a/src/Razor/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/IRazorEditServiceExtensions.cs b/src/Razor/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/IRazorEditServiceExtensions.cs
index f115c74931785..3a1edca949d69 100644
--- a/src/Razor/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/IRazorEditServiceExtensions.cs
+++ b/src/Razor/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/IRazorEditServiceExtensions.cs
@@ -12,26 +12,6 @@ namespace Microsoft.CodeAnalysis.Remote.Razor.DocumentMapping;
internal static class IRazorEditServiceExtensions
{
-#if SONICDEV
- [System.Obsolete("PROTOTYPE(sonic): Call the overload that takes a bool to prove that you thought about which document to get")]
-#endif
- public static async Task> MapCSharpEditsAsync(
- this IRazorEditService service,
- ImmutableArray textChanges,
- RemoteDocumentSnapshot snapshot,
- CancellationToken cancellationToken)
- {
- var mappedChanges = await service.MapCSharpEditsAsync(
- textChanges.SelectAsArray(static c => c.ToRazorTextChange()),
- snapshot,
- declarationDocument: false,
- includeCSharpLanguageFeatureEdits: true,
- directlyMappedEditFilter: null,
- cancellationToken).ConfigureAwait(false);
-
- return mappedChanges.SelectAsArray(static c => c.ToTextChange());
- }
-
public static async Task> MapCSharpEditsAsync(
this IRazorEditService service,
ImmutableArray textChanges,
diff --git a/src/Razor/src/Razor/test/Microsoft.CodeAnalysis.Razor.CohostingShared.UnitTests/CodeActions/ImplementInterfaceTests.cs b/src/Razor/src/Razor/test/Microsoft.CodeAnalysis.Razor.CohostingShared.UnitTests/CodeActions/ImplementInterfaceTests.cs
index 16b57886aeae1..7081cffaab4ae 100644
--- a/src/Razor/src/Razor/test/Microsoft.CodeAnalysis.Razor.CohostingShared.UnitTests/CodeActions/ImplementInterfaceTests.cs
+++ b/src/Razor/src/Razor/test/Microsoft.CodeAnalysis.Razor.CohostingShared.UnitTests/CodeActions/ImplementInterfaceTests.cs
@@ -289,7 +289,7 @@ public interface IDerived : IBase
makeDiagnosticsRequest: true);
}
- [Fact(Skip = "PROTOTYPE(sonic): cohost ImplementInterface positions members mid-@code-block with the decl/impl split; see https://github.com/dotnet/roslyn/issues/84609")]
+ [Fact]
public async Task ImplementInterface_Explicitly_PartialBaseImplementations_AddsDerivedMembers()
{
await VerifyCodeActionAsync(
@@ -324,6 +324,9 @@ @implements IDerived
int IBase.this[int index] { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
string IBase.Property1 { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
+ string IDerived.Property1 { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
+
+ int IDerived.this[int index] { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
event EventHandler IBase.Event1
{
@@ -338,10 +341,6 @@ event EventHandler IBase.Event1
}
}
- int IDerived.this[int index] { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
-
- string IDerived.Property1 { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
-
event EventHandler IDerived.Event1
{
add
diff --git a/src/Razor/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/RazorCodeDocumentTestExtensions.cs b/src/Razor/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/RazorCodeDocumentTestExtensions.cs
new file mode 100644
index 0000000000000..c6faea5bee7ee
--- /dev/null
+++ b/src/Razor/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/RazorCodeDocumentTestExtensions.cs
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Microsoft.AspNetCore.Razor.Language;
+
+///
+/// Test-only conveniences for reaching the implementation or declaration half of a
+/// by name. Production code calls
+/// /
+/// directly so the decl/impl choice
+/// is spelled out at the call site; tests keep the shorter names, which live here rather than on the
+/// production type.
+///
+public static class RazorCodeDocumentTestExtensions
+{
+ public static RazorCSharpDocument? GetImplCSharpDocument(this RazorCodeDocument document)
+ => document.GetCSharpDocument(declarationDocument: false);
+
+ public static RazorCSharpDocument GetRequiredImplCSharpDocument(this RazorCodeDocument document)
+ => document.GetRequiredCSharpDocument(declarationDocument: false);
+
+ public static RazorCSharpDocument? GetDeclCSharpDocument(this RazorCodeDocument document)
+ => document.GetCSharpDocument(declarationDocument: true);
+}