| File: CommandLine\CommonCompiler.ExistingReferencesResolver.cs | Web Access |
| Project: src\roslyn\src\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj (Microsoft.CodeAnalysis) |
// 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. using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.IO; using System.Linq; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis { internal abstract partial class CommonCompiler { /// <summary> /// Looks for metadata references among the assembly file references given to the compilation when constructed. /// When scripts are included into a project we don't want #r's to reference other assemblies than those /// specified explicitly in the project references. /// </summary> internal sealed class ExistingReferencesResolver : MetadataReferenceResolver, IEquatable<ExistingReferencesResolver> { private readonly MetadataReferenceResolver _resolver; private readonly ImmutableArray<MetadataReference> _availableReferences; private readonly Lazy<HashSet<AssemblyIdentity>> _lazyAvailableReferences; public ExistingReferencesResolver(MetadataReferenceResolver resolver, ImmutableArray<MetadataReference> availableReferences) { Debug.Assert(resolver != null); Debug.Assert(availableReferences != null); _resolver = resolver; _availableReferences = availableReferences; // Delay reading assembly identities until they are actually needed (only when #r is encountered). _lazyAvailableReferences = new Lazy<HashSet<AssemblyIdentity>>(() => new HashSet<AssemblyIdentity>( from reference in _availableReferences let identity = TryGetIdentity(reference) where identity != null select identity!)); } public override ImmutableArray<PortableExecutableReference> ResolveReference(string reference, string? baseFilePath, MetadataReferenceProperties properties) { var resolvedReferences = _resolver.ResolveReference(reference, baseFilePath, properties); return resolvedReferences.WhereAsArray(r => _lazyAvailableReferences.Value.Contains(TryGetIdentity(r)!)); } private static AssemblyIdentity? TryGetIdentity(MetadataReference metadataReference) { var peReference = metadataReference as PortableExecutableReference; if (peReference == null || peReference.Properties.Kind != MetadataImageKind.Assembly) { return null; } try { PEAssembly assembly = ((AssemblyMetadata)peReference.GetMetadataNoCopy()).GetAssembly()!; return assembly.Identity; } catch (Exception e) when (e is BadImageFormatException || e is IOException) { // ignore, metadata reading errors are reported by the compiler for the existing references return null; } } public override int GetHashCode() { return _resolver.GetHashCode(); } public bool Equals(ExistingReferencesResolver? other) { return other is object && _resolver.Equals(other._resolver) && _availableReferences.SequenceEqual(other._availableReferences); } public override bool Equals(object? other) => other is ExistingReferencesResolver obj && Equals(obj); } } }