Add support for System.Diagnostics.CodeAnalysis.ExperimentalAttribute#68702
Add support for System.Diagnostics.CodeAnalysis.ExperimentalAttribute#68702jcouv merged 8 commits intodotnet:mainfrom
System.Diagnostics.CodeAnalysis.ExperimentalAttribute#68702Conversation
|
|
||
| // 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.
Is FormattedSymbol necessary? Isn't CSharpErrorMessageFormat the default? #Resolved
| : 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.
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.
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.
Pinged to fix the design doc at dotnet/designs@183cee7#r119278540
| namespace Microsoft.CodeAnalysis.CSharp.UnitTests | ||
| { | ||
| public class AttributeTests_Experimental : CSharpTestBase | ||
| public class AttributeTests_WindowsExperimental : CSharpTestBase |
There was a problem hiding this comment.
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.
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.
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.
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.
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.
Consider testing suppression using SuppressMessageAttribute. #Resolved
There was a problem hiding this comment.
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.
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.
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.
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 ( |
| throw ExceptionUtilities.UnexpectedValue(kind); | ||
| } | ||
|
|
||
| ObsoleteAttributeData decodeExperimentalAttribute() |
| 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.
It looks like the WindowsExperimentalAttribute case and the ExperimentalAttribute case are identical. Consider dropping one. #Resolved
There was a problem hiding this comment.
Many of the cases in here are identical. I'd rather stick to the existing structure.
| 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) |
| Case AttributeDescription.CaseInsensitiveExtensionAttribute.Name, | ||
| AttributeDescription.ObsoleteAttribute.Name, | ||
| AttributeDescription.DeprecatedAttribute.Name, | ||
| AttributeDescription.WindowsExperimentalAttribute.Name, |
| ]]></expected>) | ||
| End Sub | ||
|
|
||
| Private ReadOnly experimentalAttributeCSharpSrc As String = " |
| 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.
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.
Tagging @BillWagner here as well (this is an existing diagnostic code)
|
|
||
| comp.AssertTheseDiagnostics( | ||
| <expected><)
// C.M();
Diagnostic("DiagID1", "C").WithArguments("C").WithLocation(1, 1)
There was a problem hiding this comment.
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 |
| 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.
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. |
| """; | ||
| 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.
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)