From c8a0fa0ba1fa67718a6bdf4b9fbc93a9bf647ac5 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Tue, 1 Aug 2023 22:04:31 -0700 Subject: [PATCH] VB implementation --- .../VisualBasic/CompilationTestUtils.vb | 13 + .../Test/Utilities/VisualBasic/MockSymbols.vb | 14 + .../Portable/Symbols/AssemblySymbol.vb | 10 - .../Symbols/Metadata/PE/PEAssemblySymbol.vb | 27 ++ .../Symbols/Metadata/PE/PEModuleSymbol.vb | 27 ++ .../Portable/Symbols/MissingAssemblySymbol.vb | 7 + .../Portable/Symbols/MissingModuleSymbol.vb | 7 + .../Portable/Symbols/ModuleSymbol.vb | 10 - .../Symbols/ObsoleteAttributeHelpers.vb | 62 ++- .../Retargeting/RetargetingAssemblySymbol.vb | 7 + .../Retargeting/RetargetingModuleSymbol.vb | 7 + .../Symbols/Source/SourceAssemblySymbol.vb | 20 +- .../Symbols/Source/SourceModuleSymbol.vb | 14 + .../VisualBasic/Portable/Symbols/Symbol.vb | 17 + .../Test/Emit/Attributes/AttributeTests.vb | 455 +++++++++++++++++- 15 files changed, 668 insertions(+), 29 deletions(-) diff --git a/src/Compilers/Test/Utilities/VisualBasic/CompilationTestUtils.vb b/src/Compilers/Test/Utilities/VisualBasic/CompilationTestUtils.vb index a39b2dd93158a..410cdd9e098b7 100644 --- a/src/Compilers/Test/Utilities/VisualBasic/CompilationTestUtils.vb +++ b/src/Compilers/Test/Utilities/VisualBasic/CompilationTestUtils.vb @@ -33,6 +33,19 @@ Friend Module CompilationUtils Return CreateEmptyCompilation(source, references, options, parseOptions, assemblyName) End Function + Public Function CreateCompilationWithIdentity( + identity As AssemblyIdentity, + source As BasicTestSource, + Optional references As IEnumerable(Of MetadataReference) = Nothing, + Optional targetFramework As TargetFramework = TargetFramework.StandardAndVBRuntime) As VisualBasicCompilation + + Dim c = CreateCompilation(source, references, assemblyName:=identity.Name) + Assert.NotNull(c.Assembly) ' force creation Of SourceAssemblySymbol + DirectCast(c.Assembly, SourceAssemblySymbol).m_lazyIdentity = identity + + Return c + End Function + Public Function CreateEmptyCompilation( source As BasicTestSource, Optional references As IEnumerable(Of MetadataReference) = Nothing, diff --git a/src/Compilers/Test/Utilities/VisualBasic/MockSymbols.vb b/src/Compilers/Test/Utilities/VisualBasic/MockSymbols.vb index 28cdd322f7cec..ebbfcf124a727 100644 --- a/src/Compilers/Test/Utilities/VisualBasic/MockSymbols.vb +++ b/src/Compilers/Test/Utilities/VisualBasic/MockSymbols.vb @@ -747,6 +747,13 @@ Friend Class MockModuleSymbol Public Overrides Function GetMetadata() As ModuleMetadata Return Nothing End Function + + Friend NotOverridable Overrides ReadOnly Property ObsoleteAttributeData As ObsoleteAttributeData + Get + Return Nothing + End Get + End Property + End Class Friend Class MockAssemblySymbol @@ -861,4 +868,11 @@ Friend Class MockAssemblySymbol Public Overrides Function GetMetadata() As AssemblyMetadata Return Nothing End Function + + Friend Overrides ReadOnly Property ObsoleteAttributeData As ObsoleteAttributeData + Get + Return Nothing + End Get + End Property + End Class diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb index 09e42621e0c18..74da0a0cb68e4 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb @@ -238,16 +238,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - ''' - ''' Returns data decoded from Obsolete attribute or null if there is no Obsolete attribute. - ''' This property returns ObsoleteAttributeData.Uninitialized if attribute arguments haven't been decoded yet. - ''' - Friend NotOverridable Overrides ReadOnly Property ObsoleteAttributeData As ObsoleteAttributeData - Get - Return Nothing - End Get - End Property - ''' ''' Lookup a top level type referenced from metadata, names should be ''' compared case-sensitively. diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEAssemblySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEAssemblySymbol.vb index 9306bafa7931c..9afeb9cc2a8cd 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEAssemblySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEAssemblySymbol.vb @@ -68,6 +68,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Private _lazyCachedCompilerFeatureRequiredDiagnosticInfo As DiagnosticInfo = ErrorFactory.EmptyDiagnosticInfo + Private _lazyObsoleteAttributeData As ObsoleteAttributeData = ObsoleteAttributeData.Uninitialized + Friend Sub New(assembly As PEAssembly, documentationProvider As DocumentationProvider, isLinked As Boolean, importOptions As MetadataImportOptions) Debug.Assert(assembly IsNot Nothing) @@ -286,5 +288,30 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Return MyBase.HasUnsupportedMetadata End Get End Property + + ''' + ''' Returns data decoded from Obsolete attribute or null if there is no Obsolete/Experimental/... attribute. + ''' This property returns ObsoleteAttributeData.Uninitialized if attribute arguments haven't been decoded yet. + ''' + Friend Overrides ReadOnly Property ObsoleteAttributeData As ObsoleteAttributeData + Get + If _lazyObsoleteAttributeData Is ObsoleteAttributeData.Uninitialized Then + Interlocked.CompareExchange(_lazyObsoleteAttributeData, ComputeObsoleteAttributeData(), ObsoleteAttributeData.Uninitialized) + End If + + Return _lazyObsoleteAttributeData + End Get + End Property + + Private Function ComputeObsoleteAttributeData() As ObsoleteAttributeData + For Each attrData In GetAttributes() + If attrData.IsTargetAttribute(Me, AttributeDescription.ExperimentalAttribute) Then + Return attrData.DecodeExperimentalAttribute() + End If + Next + + Return Nothing + End Function + End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEModuleSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEModuleSymbol.vb index e6af8729c47d5..5045e4a594d9c 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEModuleSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEModuleSymbol.vb @@ -81,6 +81,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Private _lazyCachedCompilerFeatureRequiredDiagnosticInfo As DiagnosticInfo = ErrorFactory.EmptyDiagnosticInfo + Private _lazyObsoleteAttributeData As ObsoleteAttributeData = ObsoleteAttributeData.Uninitialized + Friend Sub New(assemblySymbol As PEAssemblySymbol, [module] As PEModule, importOptions As MetadataImportOptions, ordinal As Integer) Me.New(DirectCast(assemblySymbol, AssemblySymbol), [module], importOptions, ordinal) Debug.Assert(ordinal >= 0) @@ -507,5 +509,30 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Return MyBase.HasUnsupportedMetadata End Get End Property + + ''' + ''' Returns data decoded from Obsolete attribute or null if there is no Obsolete/Experimental/... attribute. + ''' This property returns ObsoleteAttributeData.Uninitialized if attribute arguments haven't been decoded yet. + ''' + Friend Overrides ReadOnly Property ObsoleteAttributeData As ObsoleteAttributeData + Get + If _lazyObsoleteAttributeData Is ObsoleteAttributeData.Uninitialized Then + Interlocked.CompareExchange(_lazyObsoleteAttributeData, ComputeObsoleteAttributeData(), ObsoleteAttributeData.Uninitialized) + End If + + Return _lazyObsoleteAttributeData + End Get + End Property + + Private Function ComputeObsoleteAttributeData() As ObsoleteAttributeData + For Each attrData In GetAttributes() + If attrData.IsTargetAttribute(Me, AttributeDescription.ExperimentalAttribute) Then + Return attrData.DecodeExperimentalAttribute() + End If + Next + + Return Nothing + End Function + End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Symbols/MissingAssemblySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/MissingAssemblySymbol.vb index c6a1d7d5a4936..8e84e812e0bf9 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/MissingAssemblySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/MissingAssemblySymbol.vb @@ -165,6 +165,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Public Overrides Function GetMetadata() As AssemblyMetadata Return Nothing End Function + + Friend Overrides ReadOnly Property ObsoleteAttributeData As ObsoleteAttributeData + Get + Return Nothing + End Get + End Property + End Class ''' diff --git a/src/Compilers/VisualBasic/Portable/Symbols/MissingModuleSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/MissingModuleSymbol.vb index 5c62aa12a50db..1d88e088a130b 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/MissingModuleSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/MissingModuleSymbol.vb @@ -171,6 +171,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Public Overrides Function GetMetadata() As ModuleMetadata Return Nothing End Function + + Friend NotOverridable Overrides ReadOnly Property ObsoleteAttributeData As ObsoleteAttributeData + Get + Return Nothing + End Get + End Property + End Class Friend Class MissingModuleSymbolWithName diff --git a/src/Compilers/VisualBasic/Portable/Symbols/ModuleSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/ModuleSymbol.vb index 2753e72de51d0..3dcb5d16caef4 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/ModuleSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/ModuleSymbol.vb @@ -293,16 +293,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' Friend MustOverride ReadOnly Property MightContainExtensionMethods As Boolean - ''' - ''' Returns data decoded from Obsolete attribute or null if there is no Obsolete attribute. - ''' This property returns ObsoleteAttributeData.Uninitialized if attribute arguments haven't been decoded yet. - ''' - Friend NotOverridable Overrides ReadOnly Property ObsoleteAttributeData As ObsoleteAttributeData - Get - Return Nothing - End Get - End Property - #Region "IModuleSymbol" Private ReadOnly Property IModuleSymbol_GlobalNamespace As INamespaceSymbol Implements IModuleSymbol.GlobalNamespace Get diff --git a/src/Compilers/VisualBasic/Portable/Symbols/ObsoleteAttributeHelpers.vb b/src/Compilers/VisualBasic/Portable/Symbols/ObsoleteAttributeHelpers.vb index e8367ab52beb4..c248a2875a39e 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/ObsoleteAttributeHelpers.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/ObsoleteAttributeHelpers.vb @@ -46,13 +46,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' symbol's Obsoleteness is Unknown. False, if we are certain that no symbol in the parent ''' hierarchy is Obsolete. ''' - Private Shared Function GetObsoleteContextState(symbol As Symbol, forceComplete As Boolean) As ThreeState + Private Shared Function GetObsoleteContextState(symbol As Symbol, forceComplete As Boolean, getStateFromSymbol As Func(Of Symbol, ThreeState)) As ThreeState While symbol IsNot Nothing If forceComplete Then symbol.ForceCompleteObsoleteAttribute() End If - Dim state = symbol.ObsoleteState + Dim state = getStateFromSymbol(symbol) If state <> ThreeState.False Then Return state End If @@ -72,11 +72,39 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Debug.Assert(context IsNot Nothing) Debug.Assert(symbol IsNot Nothing) + Dim namedType = TryCast(symbol, NamedTypeSymbol) + If namedType IsNot Nothing AndAlso + IsExperimentalSymbol(namedType) Then + + ' Skip for System.Diagnostics.CodeAnalysis.ExperimentalAttribute to mitigate cycles + Return ObsoleteDiagnosticKind.NotObsolete + End If + + Dim method = TryCast(symbol, MethodSymbol) + If method IsNot Nothing AndAlso + method.MethodKind = MethodKind.Constructor AndAlso + IsExperimentalSymbol(method.ContainingType) Then + + ' Skip for constructors of System.Diagnostics.CodeAnalysis.ExperimentalAttribute to mitigate cycles + Return ObsoleteDiagnosticKind.NotObsolete + End If + + Debug.Assert(symbol.ContainingModule Is Nothing OrElse symbol.ContainingModule.ObsoleteKind <> ObsoleteAttributeKind.Uninitialized) + Debug.Assert(symbol.ContainingAssembly Is Nothing OrElse symbol.ContainingAssembly.ObsoleteKind <> ObsoleteAttributeKind.Uninitialized) + + If symbol.ContainingModule?.ObsoleteKind = ObsoleteAttributeKind.Experimental OrElse + symbol.ContainingAssembly?.ObsoleteKind = ObsoleteAttributeKind.Experimental Then + + Return GetExperimentalDiagnosticKind(context, forceComplete) + End If + Select Case symbol.ObsoleteKind Case ObsoleteAttributeKind.None Return ObsoleteDiagnosticKind.NotObsolete - Case ObsoleteAttributeKind.WindowsExperimental, ObsoleteAttributeKind.Experimental + Case ObsoleteAttributeKind.WindowsExperimental Return ObsoleteDiagnosticKind.Diagnostic + Case ObsoleteAttributeKind.Experimental + Return GetExperimentalDiagnosticKind(context, forceComplete) Case ObsoleteAttributeKind.Uninitialized ' If we haven't cracked attributes on the symbol at all or we haven't ' cracked attribute arguments enough to be able to report diagnostics for @@ -85,7 +113,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return ObsoleteDiagnosticKind.Lazy End Select - Select Case GetObsoleteContextState(context, forceComplete) + Select Case GetObsoleteContextState(context, forceComplete, getStateFromSymbol:=Function(s) s.ObsoleteState) Case ThreeState.False Return ObsoleteDiagnosticKind.Diagnostic Case ThreeState.True @@ -99,12 +127,36 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Select End Function + Private Shared Function IsExperimentalSymbol(namedType As NamedTypeSymbol) As Boolean + Return namedType IsNot Nothing AndAlso + namedType.Arity = 0 AndAlso + namedType.HasNameQualifier("System.Diagnostics.CodeAnalysis", StringComparison.Ordinal) AndAlso + namedType.Name.Equals("ExperimentalAttribute", StringComparison.Ordinal) + End Function + + Private Shared Function GetExperimentalDiagnosticKind(containingMember As Symbol, forceComplete As Boolean) As ObsoleteDiagnosticKind + + Select Case GetObsoleteContextState(containingMember, forceComplete, getStateFromSymbol:=Function(s) s.ExperimentalState) + Case ThreeState.False + Return ObsoleteDiagnosticKind.Diagnostic + Case ThreeState.True + ' If we are in a context that is already experimental, there is no point reporting + ' more experimental diagnostics. + Return ObsoleteDiagnosticKind.Suppressed + Case Else + ' If the context is unknown, then store the symbol so that we can do this check at a + ' later stage + Return ObsoleteDiagnosticKind.LazyPotentiallySuppressed + End Select + End Function + ''' ''' Create a diagnostic for the given symbol. This could be an error or a warning based on ''' the ObsoleteAttribute's arguments. ''' Friend Shared Function CreateObsoleteDiagnostic(symbol As Symbol) As DiagnosticInfo - Dim data = symbol.ObsoleteAttributeData + Dim data = If(If(symbol.ObsoleteAttributeData, symbol.ContainingModule.ObsoleteAttributeData), symbol.ContainingAssembly.ObsoleteAttributeData) + Debug.Assert(data IsNot Nothing) If data Is Nothing Then diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingAssemblySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingAssemblySymbol.vb index 00d063d90fb91..20100cef60f05 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingAssemblySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingAssemblySymbol.vb @@ -268,5 +268,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting Public Overrides Function GetMetadata() As AssemblyMetadata Return _underlyingAssembly.GetMetadata() End Function + + Friend Overrides ReadOnly Property ObsoleteAttributeData As ObsoleteAttributeData + Get + Return _underlyingAssembly.ObsoleteAttributeData + End Get + End Property + End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingModuleSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingModuleSymbol.vb index ed1cd2fc52464..99987031c11fc 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingModuleSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingModuleSymbol.vb @@ -290,5 +290,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting Public Overrides Function GetMetadata() As ModuleMetadata Return _underlyingModule.GetMetadata() End Function + + Friend Overrides ReadOnly Property ObsoleteAttributeData As ObsoleteAttributeData + Get + Return _underlyingModule.ObsoleteAttributeData + End Get + End Property + End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb index 7e522d31b6a95..f452e2071f15e 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb @@ -5,10 +5,7 @@ Imports System.Collections.Concurrent Imports System.Collections.Immutable Imports System.Reflection -Imports System.Reflection.Metadata -Imports System.Runtime.CompilerServices Imports System.Runtime.InteropServices -Imports System.Security.Cryptography Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Symbols @@ -1092,6 +1089,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols arguments.GetOrCreateData(Of CommonAssemblyWellKnownAttributeData)().RuntimeCompatibilityWrapNonExceptionThrows = True ElseIf attrData.IsTargetAttribute(Me, AttributeDescription.DebuggableAttribute) Then arguments.GetOrCreateData(Of CommonAssemblyWellKnownAttributeData)().HasDebuggableAttribute = True + ElseIf attrData.IsTargetAttribute(Me, AttributeDescription.ExperimentalAttribute) Then + arguments.GetOrCreateData(Of CommonAssemblyWellKnownAttributeData)().ObsoleteAttributeData = attrData.DecodeExperimentalAttribute() Else Dim signature As Integer = attrData.GetTargetAttributeSignatureIndex(Me, AttributeDescription.AssemblyAlgorithmIdAttribute) @@ -1780,5 +1779,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return _compilation End Get End Property + + ''' + ''' Returns data decoded from Experimental attribute or null if there is no Obsolete/Experimental/... attribute. + ''' This property returns ObsoleteAttributeData.Uninitialized if attribute arguments haven't been decoded yet. + ''' + Friend Overrides ReadOnly Property ObsoleteAttributeData As ObsoleteAttributeData + Get + ' may have been specified in the assembly or one of the modules + Dim result = If(GetSourceDecodedWellKnownAttributeData()?.ObsoleteAttributeData, GetNetModuleDecodedWellKnownAttributeData()?.ObsoleteAttributeData) + + Debug.Assert(result Is Nothing OrElse result.Kind = ObsoleteAttributeKind.Experimental) + Return result + End Get + End Property + End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceModuleSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceModuleSymbol.vb index e208ec8ce966b..4497afd79c5c6 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceModuleSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceModuleSymbol.vb @@ -1116,6 +1116,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End If ElseIf attrData.IsTargetAttribute(Me, AttributeDescription.DebuggableAttribute) Then arguments.GetOrCreateData(Of CommonModuleWellKnownAttributeData).HasDebuggableAttribute = True + ElseIf attrData.IsTargetAttribute(Me, AttributeDescription.ExperimentalAttribute) Then + arguments.GetOrCreateData(Of CommonModuleWellKnownAttributeData).ObsoleteAttributeData = attrData.DecodeObsoleteAttribute(ObsoleteAttributeKind.Experimental) End If MyBase.DecodeWellKnownAttribute(arguments) @@ -1220,5 +1222,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Public Overrides Function GetMetadata() As ModuleMetadata Return Nothing End Function + + ''' + ''' Returns data decoded from Experimental attribute or null if there is no Obsolete/Experimental/... attribute. + ''' This property returns ObsoleteAttributeData.Uninitialized if attribute arguments haven't been decoded yet. + ''' + Friend Overrides ReadOnly Property ObsoleteAttributeData As ObsoleteAttributeData + Get + Dim data = GetDecodedWellKnownAttributeData() + Return If(data IsNot Nothing, data.ObsoleteAttributeData, Nothing) + End Get + End Property + End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Symbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Symbol.vb index 9771862391d5d..49e052acacd84 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Symbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Symbol.vb @@ -456,6 +456,23 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property + ''' + ''' True if this symbol has been marked with the Experimental attribute. + ''' This property returns Unknown if the Experimental attribute hasn't been cracked yet. + ''' + Friend ReadOnly Property ExperimentalState As ThreeState + Get + Select Case ObsoleteKind + Case ObsoleteAttributeKind.Experimental + Return ThreeState.True + Case ObsoleteAttributeKind.Uninitialized + Return ThreeState.Unknown + Case Else + Return ThreeState.False + End Select + End Get + End Property + Friend ReadOnly Property ObsoleteKind As ObsoleteAttributeKind Get Dim data = Me.ObsoleteAttributeData diff --git a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb index a41614fd8878e..a48d45ea8c780 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb @@ -5,12 +5,14 @@ Imports System.Collections.Immutable Imports System.IO Imports System.Reflection +Imports System.Resources Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis.Emit Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE +Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities @@ -5067,7 +5069,7 @@ DiagID1: 'C' is for evaluation purposes only and is subject to change or removal ~ ]]>) - Dim diag = Comp.GetDiagnostics().Single() + Dim diag = comp.GetDiagnostics().Single() Assert.Equal("DiagID1", diag.Id) Assert.Equal(ERRID.WRN_Experimental, diag.Code) Assert.Equal("https://example.org/DiagID1", diag.Descriptor.HelpLinkUri) @@ -5111,5 +5113,456 @@ DiagID1: 'C' is for evaluation purposes only and is subject to change or removal Assert.Equal("https://example.org/DiagID1", diag.Descriptor.HelpLinkUri) End Sub + + Public Sub OnAssembly_UsedFromSource() + Dim attrComp = CreateCSharpCompilation(experimentalAttributeCSharpSrc) + + Dim src = + + + +Class C +End Class + +Class D + Sub M(c As C) + End Sub +End Class +]]> + + + + Dim comp = CreateCompilation(src, references:={attrComp.EmitToImageReference()}) + comp.AssertNoDiagnostics() + + Assert.Equal(ObsoleteAttributeKind.None, comp.GetTypeByMetadataName("C").ContainingModule.ObsoleteKind) + Assert.Equal(ObsoleteAttributeKind.Experimental, comp.GetTypeByMetadataName("C").ContainingAssembly.ObsoleteKind) + End Sub + + + Public Sub OnAssembly_UsedFromMetadata() + Dim attrComp = CreateCSharpCompilation(experimentalAttributeCSharpSrc) + Dim attrRef = attrComp.EmitToImageReference() + + Dim libSrc = + + + +Public Class C +End Class +]]> + + + Dim libComp = CreateCompilation(libSrc, references:={attrRef}) + Dim libRef = libComp.EmitToImageReference() + + Dim src = + + + + + + Dim comp = CreateCompilation(src, references:={libRef, attrRef}) + + comp.AssertTheseDiagnostics( +) + + Assert.Equal(ObsoleteAttributeKind.None, comp.GetTypeByMetadataName("C").ContainingModule.ObsoleteKind) + Assert.Equal(ObsoleteAttributeKind.Experimental, comp.GetTypeByMetadataName("C").ContainingAssembly.ObsoleteKind) + + 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) + End Sub + + + Public Sub OnAssembly_CompiledIntoModule() + Dim attrComp = CreateCSharpCompilation(experimentalAttributeCSharpSrc) + Dim attrRef = attrComp.EmitToImageReference() + + Dim libSrc = + + + +Public Class C + Public Shared Sub M() + End Sub +End Class +]]> + + + + Dim moduleComp = CreateCompilation(libSrc, options:=TestOptions.ReleaseModule, references:={attrRef}) + moduleComp.VerifyDiagnostics() + Dim moduleRef = moduleComp.EmitToImageReference() + + Dim libSrc2 = + + + + + + Dim assemblyComp = CreateCompilation(libSrc2, references:={moduleRef, attrRef}) + assemblyComp.VerifyDiagnostics() + Dim assemblyRef = assemblyComp.EmitToImageReference() + + Dim src = + + + + + + ' Since the module is referenced but not linked, we also need it here, but as + ' a result the diagnostics are suppressed + Dim comp = CreateCompilation(src, references:={assemblyRef, moduleRef, attrRef}) + comp.VerifyDiagnostics() + + Assert.Equal(ObsoleteAttributeKind.None, comp.GetTypeByMetadataName("C").ContainingModule.ObsoleteKind) + Assert.Equal(ObsoleteAttributeKind.Experimental, comp.GetTypeByMetadataName("C").ContainingAssembly.ObsoleteKind) + + Assert.Equal(ObsoleteAttributeKind.None, comp.GetTypeByMetadataName("D").ContainingModule.ObsoleteKind) + Assert.Equal(ObsoleteAttributeKind.Experimental, comp.GetTypeByMetadataName("D").ContainingAssembly.ObsoleteKind) + End Sub + + + Public Sub RetargetingAssembly_Experimental() + Dim attrComp = CreateCSharpCompilation(experimentalAttributeCSharpSrc) + Dim attrRef = attrComp.EmitToImageReference() + + Dim retargetedCode = + + + + + + Dim originalC = CreateCompilationWithIdentity(New AssemblyIdentity("Ret", New Version(1, 0, 0, 0), isRetargetable:=True), retargetedCode) + Dim retargetedC = CreateCompilationWithIdentity(New AssemblyIdentity("Ret", New Version(2, 0, 0, 0), isRetargetable:=True), retargetedCode) + + Dim derivedSrc = + + + +Class Derived + Inherits C +End Class +]]> + + + + Dim derivedComp = CreateCompilation(derivedSrc, references:={originalC.ToMetadataReference(), attrRef}) + derivedComp.AssertNoDiagnostics() + + Dim comp = CreateCompilation("", references:={derivedComp.ToMetadataReference(), retargetedC.ToMetadataReference(), attrRef}) + derivedComp.AssertNoDiagnostics() + + Dim derivedType = comp.GetTypeByMetadataName("Derived") + Assert.IsType(Of RetargetingNamedTypeSymbol)(derivedType) + Assert.IsType(Of RetargetingAssemblySymbol)(derivedType.ContainingAssembly) + Assert.Equal(ObsoleteAttributeKind.Experimental, derivedType.ContainingAssembly.ObsoleteKind) + End Sub + + + Public Sub RetargetingAssembly_NotExperimental() + Dim attrComp = CreateCSharpCompilation(experimentalAttributeCSharpSrc) + Dim attrRef = attrComp.EmitToImageReference() + + Dim retargetedCode = + + + + + + Dim originalC = CreateCompilationWithIdentity(New AssemblyIdentity("Ret", New Version(1, 0, 0, 0), isRetargetable:=True), retargetedCode) + Dim retargetedC = CreateCompilationWithIdentity(New AssemblyIdentity("Ret", New Version(2, 0, 0, 0), isRetargetable:=True), retargetedCode) + + Dim derivedSrc = + + + + + + Dim derivedComp = CreateCompilation(derivedSrc, references:={originalC.ToMetadataReference(), attrRef}) + derivedComp.AssertNoDiagnostics() + + Dim comp = CreateCompilation("", references:={derivedComp.ToMetadataReference(), retargetedC.ToMetadataReference(), attrRef}) + derivedComp.AssertNoDiagnostics() + + Dim derivedType = comp.GetTypeByMetadataName("Derived") + Assert.IsType(Of RetargetingNamedTypeSymbol)(derivedType) + Assert.IsType(Of RetargetingAssemblySymbol)(derivedType.ContainingAssembly) + Assert.Equal(ObsoleteAttributeKind.None, derivedType.ContainingAssembly.ObsoleteKind) + End Sub + + + Public Sub RetargetingModule_Experimental() + Dim attrComp = CreateCSharpCompilation(experimentalAttributeCSharpSrc) + Dim attrRef = attrComp.EmitToImageReference() + + Dim retargetedCode = + + + + + + Dim originalC = CreateCompilationWithIdentity(New AssemblyIdentity("Ret", New Version(1, 0, 0, 0), isRetargetable:=True), retargetedCode) + Dim retargetedC = CreateCompilationWithIdentity(New AssemblyIdentity("Ret", New Version(2, 0, 0, 0), isRetargetable:=True), retargetedCode) + + Dim derivedSrc = + + + +Class Derived + Inherits C +End Class +]]> + + + + Dim derivedComp = CreateCompilation(derivedSrc, references:={originalC.ToMetadataReference(), attrRef}) + derivedComp.AssertNoDiagnostics() + + Dim comp = CreateCompilation("", references:={derivedComp.ToMetadataReference(), retargetedC.ToMetadataReference(), attrRef}) + derivedComp.AssertNoDiagnostics() + + Dim derivedType = comp.GetTypeByMetadataName("Derived") + Assert.IsType(Of RetargetingNamedTypeSymbol)(derivedType) + Assert.IsType(Of RetargetingModuleSymbol)(derivedType.ContainingModule) + Assert.Equal(ObsoleteAttributeKind.Experimental, derivedType.ContainingModule.ObsoleteKind) + End Sub + + + Public Sub MissingAssemblyAndModule() + + Dim missingSrc = + + + + + + Dim missingRef = CreateCompilation(missingSrc, assemblyName:="missing").EmitToImageReference() + + Dim libSrc = + + + + + + Dim libRef = CreateCompilation(libSrc, references:={missingRef}).EmitToImageReference() + + Dim src = + + + + + + Dim comp = CreateCompilation(src, references:={libRef}) + + comp.AssertTheseDiagnostics() + + Dim missingType = comp.GlobalNamespace.GetTypeMember("C").BaseTypeNoUseSiteDiagnostics + Assert.True(TypeOf missingType.ContainingAssembly Is MissingAssemblySymbol) + Assert.Equal(ObsoleteAttributeKind.None, missingType.ContainingAssembly.ObsoleteKind) + Assert.True(TypeOf missingType.ContainingModule Is MissingModuleSymbol) + Assert.Equal(ObsoleteAttributeKind.None, missingType.ContainingModule.ObsoleteKind) + End Sub + + + Public Sub Cycle() + + Dim src = + + + +Namespace System.Diagnostics.CodeAnalysis + + Public Class ExperimentalAttribute + Inherits System.Attribute + + Public Sub New(diagnosticId As String) + End Sub + + Public Property UrlFormat As String + End Class +End Namespace +]]> + + + + Dim comp = CreateCompilation(src) + comp.AssertNoDiagnostics() + End Sub + + + Public Sub OnModule_UsedFromMetadata() + Dim attrComp = CreateCSharpCompilation(experimentalAttributeCSharpSrc) + Dim attrRef = attrComp.EmitToImageReference() + + Dim libSrc = + + + +Public Class C + Public Shared Sub M() + End Sub +End Class +]]> + + + + Dim libComp = CreateCompilation(libSrc, references:={attrRef}) + Dim libRef = libComp.EmitToImageReference() + + Dim src = + + + + + + Dim comp = CreateCompilation(src, references:={libRef, attrRef}) + + comp.AssertTheseDiagnostics( +) + + Assert.Equal(ObsoleteAttributeKind.Experimental, comp.GetTypeByMetadataName("C").ContainingModule.ObsoleteKind) + Assert.Equal(ObsoleteAttributeKind.None, comp.GetTypeByMetadataName("C").ContainingAssembly.ObsoleteKind) + + For Each diag In comp.GetDiagnostics() + 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) + Next + End Sub + + + Public Sub OnModuleAndAssembly() + ' Prefer reporting the module-level diagnostic + Dim attrComp = CreateCSharpCompilation(experimentalAttributeCSharpSrc) + Dim attrRef = attrComp.EmitToImageReference() + + Dim libSrc = + + + + +Public Class C + Public Shared Sub M() + End Sub +End Class +]]> + + + + Dim libComp = CreateCompilation(libSrc, references:={attrRef}) + Dim libRef = libComp.EmitToImageReference() + + Dim src = + + + + + + Dim comp = CreateCompilation(src, references:={libRef, attrRef}) + + comp.AssertTheseDiagnostics( +) + + Assert.Equal(ObsoleteAttributeKind.Experimental, comp.GetTypeByMetadataName("C").ContainingModule.ObsoleteKind) + Assert.Equal(ObsoleteAttributeKind.Experimental, comp.GetTypeByMetadataName("C").ContainingAssembly.ObsoleteKind) + + For Each diag In comp.GetDiagnostics() + Assert.Equal("DiagModule", diag.Id) + Next + End Sub + End Class End Namespace