Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for System.Diagnostics.CodeAnalysis.ExperimentalAttribute #68702

Merged
merged 8 commits into from
Jul 6, 2023

Conversation

jcouv
Copy link
Member

@jcouv jcouv commented Jun 20, 2023

This can be reviewed commit-by-commit. The second commit has renames.

Relates to https://github.com/dotnet/designs/blob/main/accepted/2023/preview-apis/preview-apis.md#compiler-behavior
Relates to dotnet/runtime#85444

The PR does not include support for assembly/module targets, but there may still be some discussion on that (dotnet/runtime#85444 (comment)).
Update: we'll keep assembly/module out-of-scope for now, we can revisit later. (comment)

@jcouv jcouv added this to the 17.7 milestone Jun 20, 2023
@jcouv jcouv self-assigned this Jun 20, 2023
@dotnet-issue-labeler dotnet-issue-labeler bot added the untriaged Issues and PRs which have not yet been triaged by a lead label Jun 20, 2023
@jcouv jcouv removed the untriaged Issues and PRs which have not yet been triaged by a lead label Jun 21, 2023
@jcouv jcouv marked this pull request as ready for review June 21, 2023 07:28
@jcouv jcouv requested a review from a team as a code owner June 21, 2023 07:28

// Provide an explicit format for fully-qualified type names.
return new CustomObsoleteDiagnosticInfo(MessageProvider.Instance, (int)ErrorCode.WRN_Experimental,
data, new FormattedSymbol(symbol, SymbolDisplayFormat.CSharpErrorMessageFormat));
Copy link
Member

@jjonescz jjonescz Jun 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is FormattedSymbol necessary? Isn't CSharpErrorMessageFormat the default? #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplified. Thanks

: CreateCompilation(src, references: new[] { CreateCompilation(new[] { libSrc, experimentalAttributeSrc }).EmitToImageReference() });

comp.VerifyDiagnostics(
// (1,1): warning DiagID1: 'C' is for evaluation purposes only and is subject to change or removal in future updates.
Copy link
Member

@jjonescz jjonescz Jun 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That looks like a spec bug. I'll let them know.
An error wouldn't work, as it would completely disallow use of the experimental API, which defeats the purpose. Errors can't be suppressed.
That doc also says any use will generate a diagnostic and the caller is expected to suppress it, with the usual means (i.e. #pragma or project-wide NoWarn).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pinged to fix the design doc at dotnet/designs@183cee7#r119278540

@@ -10,7 +10,7 @@

namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public class AttributeTests_Experimental : CSharpTestBase
public class AttributeTests_WindowsExperimental : CSharpTestBase
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also rename the file?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was intentionally not planning to rename the file. That unfortunately degrades the history and doesn't seem critical for this case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

History is only degraded when the changes to the file exceed the threshold of similarity. This one-line change would be detected by Git as a rename and features like blame would not be impacted.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the rename can be implemented in a separate commit to ensure Git tracks the rename correctly. The squash-merge anti-feature works hard to undermine core Git functionality, but again this file would not exceed the standard similarity threshold.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example where blame on GitHub shows the proper history after a file rename?
I've seen git show a rename locally, but never saw blame work.

// (1,1): warning DiagID: 'C' is for evaluation purposes only and is subject to change or removal in future updates.
// C.M();
Diagnostic("DiagID", "C").WithArguments("C").WithLocation(1, 1)
);
Copy link
Member

@jjonescz jjonescz Jun 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider verifying the Help URL is the default one here:

Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri);
``` #Resolved

""";

var src = """
#pragma warning disable DiagID1
Copy link
Member

@jjonescz jjonescz Jun 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider testing suppression using SuppressMessageAttribute. #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. But it looks like SuppressMessageAttribute doesn't work for compiler warnings, only analyzer warnings.

var src = """
C.M();

[System.Diagnostics.CodeAnalysis.Experimental(null)]
Copy link
Member

@jjonescz jjonescz Jun 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean an empty string here? Also consider testing a space only string, e.g., " ", "\n".

Suggested change
[System.Diagnostics.CodeAnalysis.Experimental(null)]
[System.Diagnostics.CodeAnalysis.Experimental("")]
``` #Resolved

}

[Fact]
public void EmptyDiagnosticId()
Copy link
Member

@jjonescz jjonescz Jun 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also consider testing a diagnostic ID with a space, e.g., "DIAG 01". Not sure if that's invalid here, but it is invalid in source generators and diagnostic analyzers. #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. There's a check in DiagnosticDescriptor that disallows whitespaces.

jcouv referenced this pull request in dotnet/designs Jun 22, 2023
@jcouv jcouv marked this pull request as draft June 22, 2023 20:47
@jcouv jcouv marked this pull request as ready for review June 22, 2023 21:10
@jcouv
Copy link
Member Author

jcouv commented Jun 22, 2023

@dotnet/roslyn-compiler for second review. Thanks

@jcouv jcouv requested a review from jjonescz June 23, 2023 18:26
@jcouv
Copy link
Member Author

jcouv commented Jun 23, 2023

@dotnet/roslyn-compiler for second review. Thanks

@jcouv
Copy link
Member Author

jcouv commented Jun 26, 2023

@dotnet/roslyn-compiler for second review. Thanks

1 similar comment
@jcouv
Copy link
Member Author

jcouv commented Jun 27, 2023

@dotnet/roslyn-compiler for second review. Thanks

@jcouv
Copy link
Member Author

jcouv commented Jun 30, 2023

@dotnet/roslyn-compiler for second review (candidate for 17.7, never mind, moved out to 17.8). Thanks

@jcouv jcouv modified the milestones: 17.7, 17.8 Jun 30, 2023
default:
throw ExceptionUtilities.UnexpectedValue(kind);
}

ObsoleteAttributeData decodeExperimentalAttribute()
Copy link
Member

@cston cston Jul 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decodeExperimentalAttribute

Consider using a regular method, rather than a local function, for consistency with the other cases in the switch above. #Closed

@@ -155,6 +155,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
result = result Or QuickAttributes.Obsolete
ElseIf Matches(name, inAttribute, AttributeDescription.DeprecatedAttribute) Then
result = result Or QuickAttributes.Obsolete
ElseIf Matches(name, inAttribute, AttributeDescription.WindowsExperimentalAttribute) Then
result = result Or QuickAttributes.Obsolete
Copy link
Member

@cston cston Jul 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the WindowsExperimentalAttribute case and the ExperimentalAttribute case are identical. Consider dropping one. #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many of the cases in here are identical. I'd rather stick to the existing structure.

@@ -328,6 +328,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
checker.AddName(AttributeDescription.CaseInsensitiveExtensionAttribute.Name, QuickAttributes.Extension)
checker.AddName(AttributeDescription.ObsoleteAttribute.Name, QuickAttributes.Obsolete)
checker.AddName(AttributeDescription.DeprecatedAttribute.Name, QuickAttributes.Obsolete)
checker.AddName(AttributeDescription.WindowsExperimentalAttribute.Name, QuickAttributes.Obsolete)
Copy link
Member

@cston cston Jul 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checker.AddName(AttributeDescription.WindowsExperimentalAttribute.Name, QuickAttributes.Obsolete)

This looks identical to the case below. Consider dropping this. #Resolved

@@ -1817,6 +1817,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Case AttributeDescription.CaseInsensitiveExtensionAttribute.Name,
AttributeDescription.ObsoleteAttribute.Name,
AttributeDescription.DeprecatedAttribute.Name,
AttributeDescription.WindowsExperimentalAttribute.Name,
Copy link
Member

@cston cston Jul 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AttributeDescription.WindowsExperimentalAttribute.Name,

Identical to the case below. Consider dropping. #Resolved

@@ -4894,5 +4893,127 @@ BC30045: Attribute constructor has a parameter of type 'Integer?', which is not
~~
]]></expected>)
End Sub

Private ReadOnly experimentalAttributeCSharpSrc As String = "
Copy link
Member

@cston cston Jul 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReadOnly

Const or Shared ReadOnly #Closed

Dim diag = comp.GetDiagnostics().Single()
Assert.Equal("DiagID1", diag.Id)
Assert.Equal(ERRID.WRN_Experimental, diag.Code)
Assert.Equal("https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(BC42380)", diag.Descriptor.HelpLinkUri)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(BC42380)

Similar to C#, the link reports this error is unrecognized currently. Is that expected?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tagging @BillWagner here as well (this is an existing diagnostic code)


comp.AssertTheseDiagnostics(
<expected><![CDATA[
DiagID1: 'C' is for evaluation purposes only and is subject to change or removal in future updates.
Copy link
Member

@cston cston Jul 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in future updates.

From C#, the URI was included in the message. Should the URI be included in the VB message too? Same question for test below. #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't follow. Here's what a C# diagnostic looks like:

            // (1,1): warning DiagID1: 'C' is for evaluation purposes only and is subject to change or removal in future updates.
            // C.M();
            Diagnostic("DiagID1", "C").WithArguments("C").WithLocation(1, 1)

Both C# and VB are re-using the existing error codes and messages from the Windows Experimental attribute. If you think we should include the URI in there, consider filing an issue.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error comment in the C# test UrlFormat() includes the URI. Is that comment correct?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see what you mean. In the case where there is a UrlFormat, the C# message does include the URI (copied below).
This is existing behavior from the Windows.Experimental attribute. I'll leave as-is.

            // 0.cs(1,1): warning DiagID1: 'C' is for evaluation purposes only and is subject to change or removal in future updates. ([https://example.org/DiagID1](https://example.org/DiagID1))
            // C.M();
            Diagnostic("DiagID1", "C").WithArguments("C").WithLocation(1, 1)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that comment correct?

Yes. The logic comes from FormatHelpLinkUri

Assert.Equal("DiagID1", diag.Id)
Assert.Equal(ERRID.WRN_Experimental, diag.Code)
Assert.Equal("https://example.org/DiagID1", diag.Descriptor.HelpLinkUri)
End Sub
Copy link
Member

@cston cston Jul 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

End Sub

Consider testing:

  • experimental symbols are reported with fully-qualifed names
  • reference to symbol marked <Experimental><Obsolete(True)> #Resolved

@jcouv jcouv requested a review from cston July 6, 2023 00:27
comp.VerifyDiagnostics(
// 0.cs(3,12): warning DiagID1: 'C' is for evaluation purposes only and is subject to change or removal in future updates.
// void M(C c)
Diagnostic("DiagID1", "C").WithArguments("C").WithLocation(3, 12)
Copy link
Member

@cston cston Jul 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Diagnostic("DiagID1", "C").WithArguments("C").WithLocation(3, 12)

Should we report an obsolete error from source as well? #WontFix

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is existing behavior from the Windows.Experimental attribute.
I'll leave as-is.


comp.AssertTheseDiagnostics(
<expected><![CDATA[
DiagID1: 'C' is for evaluation purposes only and is subject to change or removal in future updates.
Copy link
Member

@cston cston Jul 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DiagID1: 'C'

Should we report an obsolete error instead? #WontFix

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Answered elsewhere

""";
var comp = CreateCompilation(new[] { src, experimentalAttributeSrc });
comp.VerifyDiagnostics(
// 0.cs(1,1): warning DiagID1: 'C' is for evaluation purposes only and is subject to change or removal in future updates.
Copy link
Member

@cston cston Jul 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'C'

The name may not be fully-qualified. I believe the Diagnostic(...) item below may be using a different display format than the comment, and the comment appears to match what is reported in command-line errors. #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. Thanks for catching that

@jcouv jcouv requested a review from cston July 6, 2023 02:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants