Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions src/Razor/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@
<IsIntegrationTestProject>false</IsIntegrationTestProject>
<IsIntegrationTestProject Condition="$(MSBuildProjectName.EndsWith('.IntegrationTests'))">true</IsIntegrationTestProject>
<AddPublicApiAnalyzers Condition="'$(IsTestProject)' == 'true' OR '$(IsUnitTestProject)' == 'true' OR '$(IsIntegrationTestProject)' == 'true'">false</AddPublicApiAnalyzers>

<!-- PROTOTYPE(sonic): Uncomment to make the error list your todo list -->
<!--<DefineConstants>$(DefineConstants);SONICDEV</DefineConstants>-->
</PropertyGroup>
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ @rendermode Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer
Diagnostic(ErrorCode.ERR_BadArity, "TestComponent").WithArguments("Test.TestComponent<T>", "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);
Expand All @@ -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<T>' requires 1 type arguments
// [global::Test.TestComponent.__PrivateComponentRenderModeAttribute]
// x:\dir\subdir\Test\TestComponent.cshtml(13,19): error CS0305: Using the generic type 'TestComponent<T>' requires 1 type arguments
Diagnostic(ErrorCode.ERR_BadArity, "TestComponent").WithArguments("Test.TestComponent<T>", "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]
Expand Down Expand Up @@ -238,7 +237,7 @@ @rendermode Foo
CompileToAssembly(compilationResult);
}

[Fact(Skip = "PROTOTYPE(sonic): rendermode lowering doesn't emit a #line directive on the synthesized `=> <expr>` 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("""
Expand All @@ -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 `=> <expr>` 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Comment on lines 107 to 111
RazorSourceGeneratorEventSource.Log.GenerateDeclarationCodeStop(sourceItem.FilePath);
}
Expand All @@ -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)
Expand Down Expand Up @@ -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) =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<SourceGeneratedDocument?> TryGetSourceGeneratedDocumentForRazorDocumentAsync(this Project project, TextDocument razorDocument, CancellationToken cancellationToken)
{
return (await TryGetSourceGeneratedDocumentsForRazorDocumentAsync(project, razorDocument, cancellationToken).ConfigureAwait(false))?.ImplDoc;
}

/// <summary>
/// Finds source generated documents by iterating through all of them. In OOP there are better options!
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/// <summary>
/// Returns the generated <see cref="RazorCSharpDocument"/> that corresponds to the given
/// generated-source hint name. For Razor components the generator can emit two halves:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<ImmutableArray<TextChange>> MapCSharpEditsAsync(
this IRazorEditService service,
ImmutableArray<TextChange> 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<ImmutableArray<TextChange>> MapCSharpEditsAsync(
this IRazorEditService service,
ImmutableArray<TextChange> textChanges,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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
{
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// Test-only conveniences for reaching the implementation or declaration half of a
/// <see cref="RazorCodeDocument"/> by name. Production code calls
/// <see cref="RazorCodeDocument.GetCSharpDocument(bool)"/> /
/// <see cref="RazorCodeDocument.GetRequiredCSharpDocument(bool)"/> 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.
/// </summary>
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);
}
Loading