/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Symbols/ObsoleteAttributeHelpers.vb
183 строки
10 KB
AlekseyTs
Support ExperimentalAttribute.Message (#76060)
26 ноя 2024, 20:24
Не верифицирован
26 ноя 2024, 20:24
f5f8e95
Код
Авторство
О чём код?
' Licensed to the .NET Foundation under one or more agreements. ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. Imports System.Diagnostics Imports System.Reflection.Metadata Imports System.Threading Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Friend Enum ObsoleteDiagnosticKind NotObsolete Suppressed Diagnostic Lazy LazyPotentiallySuppressed End Enum Friend NotInheritable Class ObsoleteAttributeHelpers ''' <summary> ''' Initialize the ObsoleteAttributeData by fetching attributes and decoding ObsoleteAttributeData. This can be ''' done for Metadata symbol easily whereas trying to do this for source symbols could result in cycles. ''' </summary> Friend Shared Sub InitializeObsoleteDataFromMetadata(ByRef data As ObsoleteAttributeData, token As EntityHandle, containingModule As PEModuleSymbol) If data Is ObsoleteAttributeData.Uninitialized Then Dim obsoleteAttributeData As ObsoleteAttributeData = GetObsoleteDataFromMetadata(token, containingModule) Interlocked.CompareExchange(data, obsoleteAttributeData, ObsoleteAttributeData.Uninitialized) End If End Sub Friend Shared Function GetObsoleteDataFromMetadata(token As EntityHandle, containingModule As PEModuleSymbol) As ObsoleteAttributeData Dim obsoleteAttributeData As ObsoleteAttributeData = Nothing ' ignoreByRefLikeMarker := False, since VB does not support ref-like types obsoleteAttributeData = containingModule.Module.TryGetDeprecatedOrExperimentalOrObsoleteAttribute(token, New MetadataDecoder(containingModule), ignoreByRefLikeMarker:=False, ignoreRequiredMemberMarker:=True) Debug.Assert(obsoleteAttributeData Is Nothing OrElse Not obsoleteAttributeData.IsUninitialized) Return obsoleteAttributeData End Function ''' <summary> ''' This method checks to see if the given symbol is Obsolete or if any symbol in the parent hierarchy is Obsolete. ''' </summary> ''' <returns> ''' True if some symbol in the parent hierarchy is known to be Obsolete. Unknown if any ''' symbol's Obsoleteness is Unknown. False, if we are certain that no symbol in the parent ''' hierarchy is Obsolete. ''' </returns> 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 = getStateFromSymbol(symbol) If state <> ThreeState.False Then Return state End If ' For property or event accessors, check the associated property or event instead. If symbol.IsAccessor() Then symbol = DirectCast(symbol, MethodSymbol).AssociatedSymbol Else symbol = symbol.ContainingSymbol End If End While Return ThreeState.False End Function Friend Shared Function GetObsoleteDiagnosticKind(context As Symbol, symbol As Symbol, Optional forceComplete As Boolean = False) As ObsoleteDiagnosticKind Debug.Assert(context IsNot Nothing) Debug.Assert(symbol IsNot Nothing) Select Case symbol.ObsoleteKind Case ObsoleteAttributeKind.None Dim moduleObsoleteKind As ObsoleteAttributeKind? = symbol.ContainingModule?.ObsoleteKind Dim assemblyObsoleteKind As ObsoleteAttributeKind? = symbol.ContainingAssembly?.ObsoleteKind If moduleObsoleteKind = Global.Microsoft.CodeAnalysis.ObsoleteAttributeKind.Experimental OrElse assemblyObsoleteKind = Global.Microsoft.CodeAnalysis.ObsoleteAttributeKind.Experimental Then Return GetDiagnosticKind(context, forceComplete, getStateFromSymbol:=Function(s) s.ExperimentalState) End If If moduleObsoleteKind = Global.Microsoft.CodeAnalysis.ObsoleteAttributeKind.Uninitialized OrElse assemblyObsoleteKind = Global.Microsoft.CodeAnalysis.ObsoleteAttributeKind.Uninitialized Then Return ObsoleteDiagnosticKind.Lazy End If Return ObsoleteDiagnosticKind.NotObsolete Case ObsoleteAttributeKind.WindowsExperimental Return ObsoleteDiagnosticKind.Diagnostic Case ObsoleteAttributeKind.Experimental Return GetDiagnosticKind(context, forceComplete, getStateFromSymbol:=Function(s) s.ExperimentalState) 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 ' ObsoleteAttribute, store the symbol so that we can report diagnostics at a ' later stage. Return ObsoleteDiagnosticKind.Lazy End Select Return GetDiagnosticKind(context, forceComplete, getStateFromSymbol:=Function(s) s.ObsoleteState) End Function Private Shared Function GetDiagnosticKind(containingMember As Symbol, forceComplete As Boolean, getStateFromSymbol As Func(Of Symbol, ThreeState)) As ObsoleteDiagnosticKind Select Case GetObsoleteContextState(containingMember, forceComplete, getStateFromSymbol) Case ThreeState.False Return ObsoleteDiagnosticKind.Diagnostic Case ThreeState.True ' If we are in a context that is already experimental/obsolete, there is no point reporting ' more experimental/obsolete 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 ''' <summary> ''' Create a diagnostic for the given symbol. This could be an error or a warning based on ''' the ObsoleteAttribute's arguments. ''' </summary> Friend Shared Function CreateObsoleteDiagnostic(symbol As Symbol) As DiagnosticInfo Dim data = If(If(symbol.ObsoleteAttributeData, symbol.ContainingModule.ObsoleteAttributeData), symbol.ContainingAssembly.ObsoleteAttributeData) Debug.Assert(data IsNot Nothing) If data Is Nothing Then Return Nothing End If ' At this point, we are going to issue diagnostics and therefore the data shouldn't be ' uninitialized. Debug.Assert(Not data.IsUninitialized) If data.Kind = ObsoleteAttributeKind.WindowsExperimental Then Debug.Assert(data.Message Is Nothing) Debug.Assert(Not data.IsError) ' Provide an explicit format for fully-qualified type names. Return ErrorFactory.ErrorInfo(ERRID.WRN_Experimental, New FormattedSymbol(symbol, SymbolDisplayFormat.VisualBasicErrorMessageFormat), "", "") End If If data.Kind = ObsoleteAttributeKind.Experimental Then Debug.Assert(Not data.IsError) ' Provide an explicit format for fully-qualified type names. If String.IsNullOrEmpty(data.Message) Then Return New CustomObsoleteDiagnosticInfo(MessageProvider.Instance, ERRID.WRN_Experimental, data, New FormattedSymbol(symbol, SymbolDisplayFormat.VisualBasicErrorMessageFormat)) Else Return New CustomObsoleteDiagnosticInfo(MessageProvider.Instance, ERRID.WRN_ExperimentalWithMessage, data, New FormattedSymbol(symbol, SymbolDisplayFormat.VisualBasicErrorMessageFormat), data.Message) End If End If ' For property accessors we report a special diagnostic which indicates whether the getter or setter is obsolete. ' For all other symbols, report the regular diagnostic. If symbol.IsAccessor() AndAlso (DirectCast(symbol, MethodSymbol).AssociatedSymbol).Kind = SymbolKind.Property Then Dim accessorSymbol = DirectCast(symbol, MethodSymbol) Dim accessorString = If(accessorSymbol.MethodKind = MethodKind.PropertyGet, "Get", "Set") If String.IsNullOrEmpty(data.Message) Then Return ErrorFactory.ObsoleteErrorInfo(If(data.IsError, ERRID.ERR_UseOfObsoletePropertyAccessor2, ERRID.WRN_UseOfObsoletePropertyAccessor2), data, accessorString, accessorSymbol.AssociatedSymbol) Else Return ErrorFactory.ObsoleteErrorInfo(If(data.IsError, ERRID.ERR_UseOfObsoletePropertyAccessor3, ERRID.WRN_UseOfObsoletePropertyAccessor3), data, accessorString, accessorSymbol.AssociatedSymbol, data.Message) End If Else If String.IsNullOrEmpty(data.Message) Then Return ErrorFactory.ObsoleteErrorInfo(If(data.IsError, ERRID.ERR_UseOfObsoleteSymbolNoMessage1, ERRID.WRN_UseOfObsoleteSymbolNoMessage1), data, symbol) Else Return ErrorFactory.ObsoleteErrorInfo(If(data.IsError, ERRID.ERR_UseOfObsoleteSymbol2, ERRID.WRN_UseOfObsoleteSymbol2), data, symbol, data.Message) End If End If End Function End Class End Namespace