| File: Symbols\MetadataOrSourceOrRetargetingAssemblySymbol.vb | Web Access |
| Project: src\roslyn\src\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj (Microsoft.CodeAnalysis.VisualBasic) |
' 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.Concurrent Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Friend MustInherit Class MetadataOrSourceOrRetargetingAssemblySymbol Inherits NonMissingAssemblySymbol ''' <summary> ''' Determine whether this assembly has been granted access to <paramref name="potentialGiverOfAccess"></paramref>. ''' Assumes that the public key has been determined. The result will be cached. ''' </summary> ''' <param name="potentialGiverOfAccess"></param> ''' <returns></returns> ''' <remarks></remarks> Friend Function MakeFinalIVTDetermination(potentialGiverOfAccess As AssemblySymbol, assertUnexpectedGiver As Boolean) As IVTConclusion Dim result As IVTConclusion = IVTConclusion.NoRelationshipClaimed If AssembliesToWhichInternalAccessHasBeenDetermined.TryGetValue(potentialGiverOfAccess, result) Then Return result End If result = IVTConclusion.NoRelationshipClaimed ' returns an empty list if there was no IVT attribute at all for the given name ' A name w/o a key is represented by a list with an entry that is empty Dim publicKeys As IEnumerable(Of ImmutableArray(Of Byte)) = potentialGiverOfAccess.GetInternalsVisibleToPublicKeys(Me.Name) ' We have an easy out here. Suppose the assembly wanting access is ' being compiled as a module. You can only strong-name an assembly. So we are going to optimistically ' assume that it Is going to be compiled into an assembly with a matching strong name, if necessary If publicKeys.Any() AndAlso IsNetModule Then Return IVTConclusion.Match End If ' look for one that works, if none work, then return the failure for the last one examined. For Each key In publicKeys ' We pass the public key of this assembly explicitly so PerformIVTCheck does not need ' to get it from this.Identity, which would trigger an infinite recursion. result = potentialGiverOfAccess.Identity.PerformIVTCheck(Me.PublicKey, key) If result = IVTConclusion.Match Then ' Note that C# includes OrElse result = IVTConclusion.OneSignedOneNot Exit For End If Next If IsDirectlyOrIndirectlyReferenced(potentialGiverOfAccess) Then AssembliesToWhichInternalAccessHasBeenDetermined.TryAdd(potentialGiverOfAccess, result) Else Debug.Assert(Not assertUnexpectedGiver, "We are performing a check for an unrelated assembly which likely indicates a bug.") End If Return result End Function Protected Function IsDirectlyOrIndirectlyReferenced(potentialGiverOfAccess As AssemblySymbol) As Boolean Dim checkedAssemblies = PooledHashSet(Of AssemblySymbol).GetInstance() Dim queue = ArrayBuilder(Of AssemblySymbol).GetInstance( Me.Modules(0).ReferencedAssemblySymbols.Length + If(TryCast(Me, SourceAssemblySymbol)?.DeclaringCompilation.PreviousSubmission IsNot Nothing, 1, 0)) checkedAssemblies.Add(Me) Dim found As Boolean = CheckReferences(Me, potentialGiverOfAccess, checkedAssemblies, queue) While Not found AndAlso queue.Count <> 0 found = CheckReferences(queue.Pop(), potentialGiverOfAccess, checkedAssemblies, queue) End While checkedAssemblies.Free() queue.Free() Return found End Function Private Shared Function CheckReferences(current As AssemblySymbol, potentialGiverOfAccess As AssemblySymbol, checkedAssemblies As PooledHashSet(Of AssemblySymbol), queue As ArrayBuilder(Of AssemblySymbol)) As Boolean For Each [module] In current.Modules For Each referencedAssembly In [module].ReferencedAssemblySymbols If CheckReference(referencedAssembly, potentialGiverOfAccess, checkedAssemblies, queue) Then Return True End If Next Next Dim previous = TryCast(current, SourceAssemblySymbol)?.DeclaringCompilation.PreviousSubmission.Assembly If previous IsNot Nothing AndAlso CheckReference(previous, potentialGiverOfAccess, checkedAssemblies, queue) Then Return True End If Return False End Function Private Shared Function CheckReference(referencedAssembly As AssemblySymbol, potentialGiverOfAccess As AssemblySymbol, checkedAssemblies As PooledHashSet(Of AssemblySymbol), queue As ArrayBuilder(Of AssemblySymbol)) As Boolean If referencedAssembly Is potentialGiverOfAccess Then Return True End If If checkedAssemblies.Add(referencedAssembly) Then queue.Push(referencedAssembly) End If Return True End Function 'EDMAURER This is a cache mapping from assemblies which we have analyzed whether or not they grant 'internals access to us to the conclusion reached. Private _assembliesToWhichInternalAccessHasBeenAnalyzed As ConcurrentDictionary(Of AssemblySymbol, IVTConclusion) Protected ReadOnly Property AssembliesToWhichInternalAccessHasBeenDetermined As ConcurrentDictionary(Of AssemblySymbol, IVTConclusion) Get If _assembliesToWhichInternalAccessHasBeenAnalyzed Is Nothing Then Interlocked.CompareExchange(_assembliesToWhichInternalAccessHasBeenAnalyzed, New ConcurrentDictionary(Of AssemblySymbol, IVTConclusion), Nothing) End If Return _assembliesToWhichInternalAccessHasBeenAnalyzed End Get End Property End Class End Namespace