/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Workspaces/VisualBasic/Portable/Recommendations/VisualBasicRecommendationServiceRunner.vb
538 строк
29 KB
Cyrus Najmabadi
Simplify
18 янв 2025, 06:46
18 янв 2025, 06:46
bc0ecf7
Код
Авторство
О чём код?
' 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.Collections.Immutable Imports System.Diagnostics.CodeAnalysis Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Recommendations Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations Partial Friend Class VisualBasicRecommendationService Private NotInheritable Class VisualBasicRecommendationServiceRunner Inherits AbstractRecommendationServiceRunner Public Sub New(context As VisualBasicSyntaxContext, filterOutOfScopeLocals As Boolean, cancellationToken As CancellationToken) MyBase.New(context, filterOutOfScopeLocals, cancellationToken) End Sub Protected Overrides Function GetLambdaParameterCount(lambdaSyntax As LambdaExpressionSyntax) As Integer Return lambdaSyntax.SubOrFunctionHeader.ParameterList.Parameters.Count End Function Public Overrides Function GetRecommendedSymbols() As RecommendedSymbols Return New RecommendedSymbols(GetSymbols()) End Function Private Overloads Function GetSymbols() As ImmutableArray(Of ISymbol) If _context.SyntaxTree.IsInNonUserCode(_context.Position, _cancellationToken) OrElse _context.SyntaxTree.IsInSkippedText(_context.Position, _cancellationToken) Then Return ImmutableArray(Of ISymbol).Empty End If Dim node = _context.TargetToken.Parent If _context.IsGlobalStatementContext Then Return GetSymbolsForGlobalStatementContext() ElseIf _context.IsRightOfNameSeparator Then If node.Kind = SyntaxKind.SimpleMemberAccessExpression Then Return GetSymbolsForMemberAccessExpression(DirectCast(node, MemberAccessExpressionSyntax)) ElseIf node.Kind = SyntaxKind.QualifiedName Then Return GetSymbolsForQualifiedNameSyntax(DirectCast(node, QualifiedNameSyntax)) End If ElseIf _context.SyntaxTree.IsQueryIntoClauseContext(_context.Position, _context.TargetToken, _cancellationToken) Then Return GetUnqualifiedSymbolsForQueryIntoContext() ElseIf _context.IsAnyExpressionContext OrElse _context.IsStatementContext OrElse _context.IsNameOfContext Then Return GetUnqualifiedSymbolsForExpressionOrStatementContext() ElseIf _context.IsTypeContext OrElse _context.IsNamespaceContext Then Return GetUnqualifiedSymbolsForType() ElseIf _context.SyntaxTree.IsLabelContext(_context.Position, _context.TargetToken, _cancellationToken) Then Return GetUnqualifiedSymbolsForLabelContext() ElseIf _context.SyntaxTree.IsRaiseEventContext(_context.Position, _context.TargetToken, _cancellationToken) Then Return GetUnqualifiedSymbolsForRaiseEvent() ElseIf _context.TargetToken.IsKind(SyntaxKind.ForKeyword) Then Dim symbols = GetUnqualifiedSymbolsForExpressionOrStatementContext().WhereAsArray(AddressOf IsWritableFieldOrLocal) Return symbols ElseIf _context.IsNamespaceDeclarationNameContext Then Return GetSymbolsForNamespaceDeclarationNameContext(Of NamespaceBlockSyntax)() ElseIf _context.IsEnumBaseListContext Then Return GetSymbolsForEnumBaseList(container:=Nothing) End If Return ImmutableArray(Of ISymbol).Empty End Function Public Overrides Function TryGetExplicitTypeOfLambdaParameter(lambdaSyntax As SyntaxNode, ordinalInLambda As Integer, <NotNullWhen(True)> ByRef explicitLambdaParameterType As ITypeSymbol) As Boolean Dim lambdaExpressionSyntax = DirectCast(lambdaSyntax, LambdaExpressionSyntax) Dim parameters = lambdaExpressionSyntax.SubOrFunctionHeader.ParameterList.Parameters If parameters.Count > ordinalInLambda Then Dim parameterSyntax = parameters(ordinalInLambda) If parameterSyntax.AsClause IsNot Nothing Then explicitLambdaParameterType = _context.SemanticModel.GetTypeInfo(parameterSyntax.AsClause.Type, _cancellationToken).Type Return explicitLambdaParameterType IsNot Nothing End If End If Return False End Function Private Function IsWritableFieldOrLocal(symbol As ISymbol) As Boolean If symbol.Kind() = SymbolKind.Field Then Dim field = DirectCast(symbol, IFieldSymbol) Return Not field.IsReadOnly AndAlso Not field.IsConst End If If symbol.Kind() = SymbolKind.Local Then Dim local = DirectCast(symbol, ILocalSymbol) Return Not local.IsConst End If Return False End Function Private Function GetSymbolsForGlobalStatementContext() As ImmutableArray(Of ISymbol) Return _context.SemanticModel.LookupSymbols(_context.TargetToken.Span.End) End Function Private Function GetUnqualifiedSymbolsForQueryIntoContext() As ImmutableArray(Of ISymbol) Dim symbols = _context.SemanticModel _ .LookupSymbols(_context.TargetToken.SpanStart, includeReducedExtensionMethods:=True) Return ImmutableArray(Of ISymbol).CastUp( symbols.OfType(Of IMethodSymbol)(). Where(Function(m) m.IsAggregateFunction()). ToImmutableArray()) End Function Private Function GetUnqualifiedSymbolsForLabelContext() As ImmutableArray(Of ISymbol) Return _context.SemanticModel.LookupLabels(_context.TargetToken.SpanStart) End Function Private Function GetUnqualifiedSymbolsForRaiseEvent() As ImmutableArray(Of ISymbol) Dim containingType = _context.SemanticModel.GetEnclosingSymbol(_context.Position, _cancellationToken).ContainingType Return _context.SemanticModel _ .LookupSymbols(_context.Position, container:=containingType) _ .WhereAsArray(Function(s) s.Kind = SymbolKind.Event AndAlso Equals(s.ContainingType, containingType)) End Function Private Function GetUnqualifiedSymbolsForType() As ImmutableArray(Of ISymbol) Dim symbols = _context.SemanticModel.LookupNamespacesAndTypes(_context.TargetToken.SpanStart) Return FilterToValidAccessibleSymbols(symbols) End Function Private Function GetUnqualifiedSymbolsForExpressionOrStatementContext() As ImmutableArray(Of ISymbol) Dim lookupPosition = _context.TargetToken.SpanStart If _context.FollowsEndOfStatement Then lookupPosition = _context.Position End If Dim symbols = If( Not _context.IsNameOfContext AndAlso _context.TargetToken.Parent.IsInStaticContext(), _context.SemanticModel.LookupStaticMembers(lookupPosition), _context.SemanticModel.LookupSymbols(lookupPosition)) If _filterOutOfScopeLocals Then symbols = symbols.WhereAsArray(Function(symbol) Not symbol.IsInaccessibleLocal(_context.Position)) End If ' GitHub #4428: When the user is typing a predicate (eg. "Enumerable.Range(0,10).Select($$") ' "Func(Of" tends to get in the way of typing "Function". Exclude System.Func from expression ' contexts, except within GetType If Not _context.TargetToken.IsKind(SyntaxKind.OpenParenToken) OrElse Not _context.TargetToken.Parent.IsKind(SyntaxKind.GetTypeExpression) Then symbols = symbols.WhereAsArray(Function(s) Not IsInEligibleDelegate(s)) End If ' Hide backing fields and events Return symbols.WhereAsArray(Function(s) FilterEventsAndGeneratedSymbols(Nothing, s)) End Function Private Shared Function IsInEligibleDelegate(s As ISymbol) As Boolean If s.IsDelegateType() Then Dim typeSymbol = DirectCast(s, ITypeSymbol) Return typeSymbol.SpecialType <> SpecialType.System_Delegate End If Return False End Function Private Function GetSymbolsForQualifiedNameSyntax(node As QualifiedNameSyntax) As ImmutableArray(Of ISymbol) ' We're in a name-only context, since if we were an expression we'd be a ' MemberAccessExpressionSyntax. Thus, let's do other namespaces and types. Dim leftHandSymbolInfo = _context.SemanticModel.GetSymbolInfo(node.Left, _cancellationToken) Dim leftHandSymbol = TryCast(leftHandSymbolInfo.Symbol, INamespaceOrTypeSymbol) Dim couldBeMergedNamespace = ContainsNamespaceCandidateSymbols(leftHandSymbolInfo) If leftHandSymbol Is Nothing AndAlso Not couldBeMergedNamespace Then Return ImmutableArray(Of ISymbol).Empty End If If TypeOf node.GetAncestor(Of AsClauseSyntax)()?.Parent Is EnumStatementSyntax Then Return GetSymbolsForEnumBaseList(leftHandSymbol) End If Dim symbols As ImmutableArray(Of ISymbol) If couldBeMergedNamespace Then symbols = leftHandSymbolInfo.CandidateSymbols.OfType(Of INamespaceSymbol)() _ .SelectMany(Function(n) _context.SemanticModel.LookupNamespacesAndTypes(node.SpanStart, n)) _ .ToImmutableArray() Else symbols = _context.SemanticModel _ .LookupNamespacesAndTypes(position:=node.SpanStart, container:=leftHandSymbol) If _context.IsNamespaceDeclarationNameContext Then Dim declarationSyntax = node.GetAncestor(Of NamespaceBlockSyntax) symbols = symbols.WhereAsArray(Function(symbol) IsNonIntersectingNamespace(symbol, declarationSyntax)) End If End If Return FilterToValidAccessibleSymbols(symbols) End Function Private Function GetSymbolsForMemberAccessExpression(node As MemberAccessExpressionSyntax) As ImmutableArray(Of ISymbol) Dim leftExpression = node.GetExpressionOfMemberAccessExpression(allowImplicitTarget:=True) If leftExpression Is Nothing Then Return ImmutableArray(Of ISymbol).Empty End If Dim leftHandTypeInfo = _context.SemanticModel.GetTypeInfo(leftExpression, _cancellationToken) Dim leftHandSymbolInfo = _context.SemanticModel.GetSymbolInfo(leftExpression, _cancellationToken) ' https://github.com/dotnet/roslyn/issues/9087: Try to speculatively bind a type as an expression for My namespace ' We'll get a type contained in the My Namespace if this is successful If leftHandTypeInfo.Type IsNot Nothing AndAlso leftHandTypeInfo.Type.Equals(leftHandSymbolInfo.Symbol) Then Dim leftHandSpeculativeBinding = _context.SemanticModel.GetSpeculativeSymbolInfo(_context.Position, leftExpression, SpeculativeBindingOption.BindAsExpression) If leftHandSpeculativeBinding.Symbol IsNot Nothing AndAlso leftHandSpeculativeBinding.Symbol.ContainingNamespace?.IsMyNamespace(_context.SemanticModel.Compilation) Then leftHandSymbolInfo = leftHandSpeculativeBinding End If End If Dim excludeInstance = False Dim excludeShared = True ' do not show shared members by default Dim useBaseReferenceAccessibility = False Dim inNameOfExpression = node.IsParentKind(SyntaxKind.NameOfExpression) Dim container As ISymbol = leftHandTypeInfo.Type If container Is Nothing AndAlso TypeOf (leftHandTypeInfo.ConvertedType) Is IArrayTypeSymbol Then container = leftHandTypeInfo.ConvertedType End If If container.IsErrorType() AndAlso leftHandSymbolInfo.Symbol IsNot Nothing Then ' TODO remove this when 531549 which causes leftHandTypeInfo to be an error type is fixed container = leftHandSymbolInfo.Symbol.GetSymbolType() End If Dim couldBeMergedNamespace = False If leftHandSymbolInfo.Symbol IsNot Nothing Then Dim firstSymbol = leftHandSymbolInfo.Symbol If firstSymbol.Kind = SymbolKind.Alias Then firstSymbol = DirectCast(firstSymbol, IAliasSymbol).Target End If Select Case firstSymbol.Kind Case SymbolKind.TypeParameter ' 884060: We don't allow invocations off type parameters. Return ImmutableArray(Of ISymbol).Empty Case SymbolKind.NamedType, SymbolKind.Namespace excludeInstance = True excludeShared = False container = DirectCast(firstSymbol, INamespaceOrTypeSymbol) End Select If firstSymbol.Kind = SymbolKind.Parameter Then Dim parameter = DirectCast(firstSymbol, IParameterSymbol) If parameter.IsMe Then excludeShared = False ' case: ' MyBase. useBaseReferenceAccessibility = Not parameter.Type.Equals(container) End If container = parameter End If ' Check for color color Dim speculativeTypeBinding = _context.SemanticModel.GetSpeculativeTypeInfo(_context.Position, leftExpression, SpeculativeBindingOption.BindAsTypeOrNamespace) Dim speculativeAliasBinding = _context.SemanticModel.GetSpeculativeAliasInfo(_context.Position, leftExpression, SpeculativeBindingOption.BindAsTypeOrNamespace) If TypeOf leftHandSymbolInfo.Symbol IsNot INamespaceOrTypeSymbol AndAlso speculativeAliasBinding Is Nothing AndAlso Equals(firstSymbol.GetSymbolType(), speculativeTypeBinding.Type) Then excludeShared = False excludeInstance = False End If If inNameOfExpression Then excludeInstance = False End If If container Is Nothing OrElse TryCast(container, ITypeSymbol)?.TypeKind = TypeKind.Enum Then excludeShared = False ' need to allow shared members for enums End If Else couldBeMergedNamespace = ContainsNamespaceCandidateSymbols(leftHandSymbolInfo) End If If container Is Nothing AndAlso Not couldBeMergedNamespace Then Return ImmutableArray(Of ISymbol).Empty End If ' We don't provide any member from System.Void (which is valid only in the context of typeof operation). ' Try to bail early to avoid unnecessary work even though compiler will handle this case for us. If container IsNot Nothing AndAlso container.Kind = SymbolKind.NamedType Then Dim typeContainer = DirectCast(container, INamedTypeSymbol) If typeContainer.IsSystemVoid() Then Return ImmutableArray(Of ISymbol).Empty End If End If Debug.Assert((Not excludeInstance OrElse Not excludeShared) OrElse (inNameOfExpression AndAlso Not excludeInstance AndAlso Not excludeShared)) Debug.Assert(Not excludeInstance OrElse Not useBaseReferenceAccessibility) ' On null conditional access, members of T for a Nullable(Of T) should be recommended Dim unwrapNullable = _context.TargetToken.GetPreviousToken().IsKind(SyntaxKind.QuestionToken) ' No completion on types/namespace after conditional access If leftExpression.Parent.IsKind(SyntaxKind.ConditionalAccessExpression) AndAlso (couldBeMergedNamespace OrElse leftHandSymbolInfo.GetBestOrAllSymbols().FirstOrDefault().MatchesKind(SymbolKind.NamedType, SymbolKind.Namespace, SymbolKind.Alias)) Then Return ImmutableArray(Of ISymbol).Empty End If Dim position = node.SpanStart Dim symbols As ImmutableArray(Of ISymbol) If couldBeMergedNamespace Then symbols = leftHandSymbolInfo.CandidateSymbols _ .OfType(Of INamespaceSymbol) _ .SelectMany(Function(n) LookupSymbolsInContainer(n, position, excludeInstance)) _ .ToImmutableArray() Else symbols = GetMemberSymbols(container, position, excludeInstance, useBaseReferenceAccessibility, unwrapNullable, isForDereference:=False) End If If excludeShared Then symbols = symbols.WhereAsArray(Function(s) Not s.IsShared) End If ' If the left expression is Me, MyBase or MyClass and we're the first statement of constructor, ' we should filter out the parenting constructor. Otherwise, we should filter out all constructors. If leftExpression.IsMeMyBaseOrMyClass() AndAlso node.IsFirstStatementInCtor() Then Dim parentingCtor = GetEnclosingCtor(node) Debug.Assert(parentingCtor IsNot Nothing) symbols = symbols.WhereAsArray(Function(s) Not s.Equals(parentingCtor)) Else symbols = symbols.WhereAsArray(Function(s) Not s.IsConstructor()) End If ' If the left expression is My.MyForms, we should filter out all non-property symbols If leftHandSymbolInfo.Symbol IsNot Nothing AndAlso leftHandSymbolInfo.Symbol.IsMyFormsProperty(_context.SemanticModel.Compilation) Then symbols = symbols.WhereAsArray(Function(s) s.Kind = SymbolKind.Property) End If ' Also filter out operators symbols = symbols.WhereAsArray(Function(s) s.Kind <> SymbolKind.Method OrElse DirectCast(s, IMethodSymbol).MethodKind <> MethodKind.UserDefinedOperator) ' Filter events and generated members symbols = symbols.WhereAsArray(Function(s) FilterEventsAndGeneratedSymbols(node, s)) ' Never show the enum backing field symbols = symbols.WhereAsArray(Function(s) s.Kind <> SymbolKind.Field OrElse Not s.ContainingType.IsEnumType() OrElse s.Name <> WellKnownMemberNames.EnumBackingFieldName) Return symbols End Function Private Shared Function ContainsNamespaceCandidateSymbols(symbolInfo As SymbolInfo) As Boolean Return symbolInfo.CandidateSymbols.Any() AndAlso symbolInfo.CandidateSymbols.All(Function(s) TypeOf s Is INamespaceSymbol) End Function ''' <summary> ''' In MemberAccessExpression Contexts, filter out event symbols (except for NameOf context), except inside AddRemoveHandler Statements ''' Also, filter out any implicitly declared members generated by event declaration or property declaration ''' </summary> Private Function FilterEventsAndGeneratedSymbols(node As MemberAccessExpressionSyntax, s As ISymbol) As Boolean If s.Kind = SymbolKind.Event AndAlso Not _context.IsNameOfContext Then Return node IsNot Nothing AndAlso node.GetAncestor(Of AddRemoveHandlerStatementSyntax) IsNot Nothing ElseIf s.Kind = SymbolKind.Field AndAlso s.IsImplicitlyDeclared Then Dim associatedSymbol = DirectCast(s, IFieldSymbol).AssociatedSymbol If associatedSymbol IsNot Nothing Then Return associatedSymbol.Kind <> SymbolKind.Event AndAlso associatedSymbol.Kind <> SymbolKind.Property End If ElseIf s.Kind = SymbolKind.NamedType AndAlso s.IsImplicitlyDeclared Then Return TypeOf DirectCast(s, INamedTypeSymbol).AssociatedSymbol IsNot IEventSymbol End If Return True End Function Private Function GetEnclosingCtor(node As MemberAccessExpressionSyntax) As IMethodSymbol Dim symbol = _context.SemanticModel.GetEnclosingSymbol(node.SpanStart, _cancellationToken) While symbol IsNot Nothing Dim method = TryCast(symbol, IMethodSymbol) If method IsNot Nothing AndAlso method.MethodKind = MethodKind.Constructor Then Return method End If End While Return Nothing End Function Private Function FilterToValidAccessibleSymbols(symbols As ImmutableArray(Of ISymbol)) As ImmutableArray(Of ISymbol) ' If this is an Inherits or Implements statement, we filter out symbols which do not recursively contain accessible, valid types. Dim inheritsContext = IsInheritsStatementContext(_context.TargetToken) Dim implementsContext = IsImplementsStatementContext(_context.TargetToken) If inheritsContext OrElse implementsContext Then Dim typeBlock = _context.TargetToken.Parent?.FirstAncestorOrSelf(Of TypeBlockSyntax)() If typeBlock IsNot Nothing Then Dim typeOrAssemblySymbol As ISymbol = _context.SemanticModel.GetDeclaredSymbol(typeBlock, _cancellationToken) If typeOrAssemblySymbol Is Nothing Then typeOrAssemblySymbol = _context.SemanticModel.Compilation.Assembly End If Dim isInterface = TryCast(typeOrAssemblySymbol, ITypeSymbol)?.TypeKind = TypeKind.Interface If inheritsContext Then ' In an interface's Inherits statement, only show interfaces. If isInterface Then Return symbols.WhereAsArray(Function(s) IsValidAccessibleInterfaceOrContainer(s, typeOrAssemblySymbol)) End If Return symbols.WhereAsArray(Function(s) IsValidAccessibleClassOrContainer(s, typeOrAssemblySymbol)) Else ' implementsContext ' In an interface's Implements statement, show nothing. If isInterface Then Return ImmutableArray(Of ISymbol).Empty End If Return symbols.WhereAsArray(Function(s) IsValidAccessibleInterfaceOrContainer(s, typeOrAssemblySymbol)) End If End If End If Return symbols End Function Private Shared Function IsInheritsStatementContext(token As SyntaxToken) As Boolean If token.IsChildToken(Of InheritsStatementSyntax)(Function(n) n.InheritsKeyword) Then Return True End If Return token.IsChildToken(Of QualifiedNameSyntax)(Function(n) n.DotToken) AndAlso token.Parent?.FirstAncestorOrSelf(Of InheritsStatementSyntax) IsNot Nothing End Function Private Shared Function IsImplementsStatementContext(token As SyntaxToken) As Boolean If token.IsChildToken(Of ImplementsStatementSyntax)(Function(n) n.ImplementsKeyword) Then Return True End If Return token.IsChildToken(Of QualifiedNameSyntax)(Function(n) n.DotToken) AndAlso token.Parent?.FirstAncestorOrSelf(Of ImplementsStatementSyntax) IsNot Nothing End Function Private Function IsValidAccessibleInterfaceOrContainer(symbol As ISymbol, within As ISymbol) As Boolean If symbol.Kind = SymbolKind.Alias Then symbol = DirectCast(symbol, IAliasSymbol).Target End If Dim namespaceSymbol = TryCast(symbol, INamespaceSymbol) If namespaceSymbol IsNot Nothing Then Return namespaceSymbol.GetMembers().Any(Function(m) IsValidAccessibleInterfaceOrContainer(m, within)) End If Dim namedTypeSymbol = TryCast(symbol, INamedTypeSymbol) If namedTypeSymbol Is Nothing Then Return False End If Return namedTypeSymbol.TypeKind = TypeKind.Interface OrElse namedTypeSymbol _ .GetAccessibleMembersInThisAndBaseTypes(Of INamedTypeSymbol)(within) _ .Any(Function(m) IsOrContainsValidAccessibleInterface(m, within)) End Function Private Function IsOrContainsValidAccessibleInterface(namespaceOrTypeSymbol As INamespaceOrTypeSymbol, within As ISymbol) As Boolean If namespaceOrTypeSymbol.Kind = SymbolKind.Namespace Then Return IsValidAccessibleInterfaceOrContainer(namespaceOrTypeSymbol, within) End If Dim namedTypeSymbol = TryCast(namespaceOrTypeSymbol, INamedTypeSymbol) If namedTypeSymbol Is Nothing Then Return False End If If namedTypeSymbol.TypeKind = TypeKind.Interface Then Return True End If Return namedTypeSymbol.GetMembers() _ .OfType(Of INamedTypeSymbol)() _ .Where(Function(m) m.IsAccessibleWithin(within)) _ .Any(Function(m) IsOrContainsValidAccessibleInterface(m, within)) End Function Private Function IsValidAccessibleClassOrContainer(symbol As ISymbol, within As ISymbol) As Boolean If symbol.Kind = SymbolKind.Alias Then symbol = DirectCast(symbol, IAliasSymbol).Target End If Dim type = TryCast(symbol, ITypeSymbol) If type IsNot Nothing Then If type.TypeKind = TypeKind.Class AndAlso Not type.IsSealed AndAlso Not Equals(type, within) Then Return True End If If type.TypeKind = TypeKind.Class OrElse type.TypeKind = TypeKind.Module OrElse type.TypeKind = TypeKind.Struct Then Return type.GetAccessibleMembersInThisAndBaseTypes(Of INamedTypeSymbol)(within).Any(Function(m) IsOrContainsValidAccessibleClass(m, within)) End If End If Dim namespaceSymbol = TryCast(symbol, INamespaceSymbol) If namespaceSymbol IsNot Nothing Then Return namespaceSymbol.GetMembers().Any(Function(m) IsValidAccessibleClassOrContainer(m, within)) End If Return False End Function Private Function IsOrContainsValidAccessibleClass(namespaceOrTypeSymbol As INamespaceOrTypeSymbol, within As ISymbol) As Boolean If namespaceOrTypeSymbol.Kind = SymbolKind.Namespace Then Return IsValidAccessibleClassOrContainer(namespaceOrTypeSymbol, within) End If Dim namedTypeSymbol = TryCast(namespaceOrTypeSymbol, INamedTypeSymbol) If namedTypeSymbol Is Nothing Then Return False End If If namedTypeSymbol.TypeKind = TypeKind.Class AndAlso Not namedTypeSymbol.IsSealed AndAlso Not Equals(namedTypeSymbol, within) Then Return True End If Return namedTypeSymbol.GetMembers() _ .OfType(Of INamedTypeSymbol)() _ .Where(Function(m) m.IsAccessibleWithin(within)) _ .Any(Function(m) IsOrContainsValidAccessibleClass(m, within)) End Function End Class End Class End Namespace