-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Conversation
|
||
// Provide an explicit format for fully-qualified type names. | ||
return new CustomObsoleteDiagnosticInfo(MessageProvider.Instance, (int)ErrorCode.WRN_Experimental, | ||
data, new FormattedSymbol(symbol, SymbolDisplayFormat.CSharpErrorMessageFormat)); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/dotnet/designs/blob/main/accepted/2023/preview-apis/preview-apis.md#compiler-behavior says "The severity is always error." but here it's a warning. #Resolved
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also rename the file?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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) | ||
); |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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)] |
There was a problem hiding this comment.
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"
.
[System.Diagnostics.CodeAnalysis.Experimental(null)] | |
[System.Diagnostics.CodeAnalysis.Experimental("")] | |
``` #Resolved |
} | ||
|
||
[Fact] | ||
public void EmptyDiagnosticId() |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
@dotnet/roslyn-compiler for second review. Thanks |
@dotnet/roslyn-compiler for second review. Thanks |
@dotnet/roslyn-compiler for second review. Thanks |
1 similar comment
@dotnet/roslyn-compiler for second review. Thanks |
@dotnet/roslyn-compiler for second review ( |
default: | ||
throw ExceptionUtilities.UnexpectedValue(kind); | ||
} | ||
|
||
ObsoleteAttributeData decodeExperimentalAttribute() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -1817,6 +1817,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols | |||
Case AttributeDescription.CaseInsensitiveExtensionAttribute.Name, | |||
AttributeDescription.ObsoleteAttribute.Name, | |||
AttributeDescription.DeprecatedAttribute.Name, | |||
AttributeDescription.WindowsExperimentalAttribute.Name, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -4894,5 +4893,127 @@ BC30045: Attribute constructor has a parameter of type 'Integer?', which is not | |||
~~ | |||
]]></expected>) | |||
End Sub | |||
|
|||
Private ReadOnly experimentalAttributeCSharpSrc As String = " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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
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)