| File: MetadataReference\PortableExecutableReference.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.IO; using System.Threading; using System.Collections.Immutable; using System.Collections.Generic; namespace Microsoft.CodeAnalysis { /// <summary> /// Reference to metadata stored in the standard ECMA-335 metadata format. /// </summary> public abstract class PortableExecutableReference : MetadataReference { private readonly string? _filePath; private DocumentationProvider? _lazyDocumentation; protected PortableExecutableReference( MetadataReferenceProperties properties, string? fullPath = null, DocumentationProvider? initialDocumentation = null) : base(properties) { _filePath = fullPath; _lazyDocumentation = initialDocumentation; } /// <summary> /// Display string used in error messages to identity the reference. /// </summary> public override string? Display { get { return FilePath; } } /// <summary> /// Path describing the location of the metadata, or null if the metadata have no location. /// </summary> public string? FilePath { get { return _filePath; } } /// <summary> /// XML documentation comments provider for the reference. /// </summary> internal DocumentationProvider DocumentationProvider { get { if (_lazyDocumentation == null) { Interlocked.CompareExchange(ref _lazyDocumentation, CreateDocumentationProvider(), null); } return _lazyDocumentation; } } /// <summary> /// Create documentation provider for the reference. /// </summary> /// <remarks> /// Called when the compiler needs to read the documentation for the reference. /// This method can be called multiple times from different threads. The result of one of the calls /// is cached on the reference object. /// </remarks> protected abstract DocumentationProvider CreateDocumentationProvider(); /// <summary> /// Returns an instance of the reference with specified aliases. /// </summary> /// <param name="aliases">The new aliases for the reference.</param> /// <exception cref="ArgumentException">Alias is invalid for the metadata kind.</exception> public new PortableExecutableReference WithAliases(IEnumerable<string> aliases) { return this.WithAliases(ImmutableArray.CreateRange(aliases)); } /// <summary> /// Returns an instance of the reference with specified aliases. /// </summary> /// <param name="aliases">The new aliases for the reference.</param> /// <exception cref="ArgumentException">Alias is invalid for the metadata kind.</exception> public new PortableExecutableReference WithAliases(ImmutableArray<string> aliases) { return WithProperties(Properties.WithAliases(aliases)); } /// <summary> /// Returns an instance of the reference with specified interop types embedding. /// </summary> /// <param name="value">The new value for <see cref="MetadataReferenceProperties.EmbedInteropTypes"/>.</param> /// <exception cref="ArgumentException">Interop types can't be embedded from modules.</exception> public new PortableExecutableReference WithEmbedInteropTypes(bool value) { return WithProperties(Properties.WithEmbedInteropTypes(value)); } /// <summary> /// Returns an instance of the reference with specified properties, or this instance if properties haven't changed. /// </summary> /// <param name="properties">The new properties for the reference.</param> /// <exception cref="ArgumentException">Specified values not valid for this reference.</exception> public new PortableExecutableReference WithProperties(MetadataReferenceProperties properties) { if (properties == this.Properties) { return this; } return WithPropertiesImpl(properties); } internal sealed override MetadataReference WithPropertiesImplReturningMetadataReference(MetadataReferenceProperties properties) { return WithPropertiesImpl(properties); } /// <summary> /// Returns an instance of the reference with specified properties. /// </summary> /// <param name="properties">The new properties for the reference.</param> /// <exception cref="NotSupportedException">Specified values not supported.</exception> /// <remarks>Only invoked if the properties changed.</remarks> protected abstract PortableExecutableReference WithPropertiesImpl(MetadataReferenceProperties properties); /// <summary> /// Get metadata representation for the PE file. /// </summary> /// <exception cref="BadImageFormatException">If the PE image format is invalid.</exception> /// <exception cref="IOException">The metadata image content can't be read.</exception> /// <exception cref="FileNotFoundException">The metadata image is stored in a file that can't be found.</exception> /// <remarks> /// Called when the <see cref="Compilation"/> needs to read the reference metadata. /// /// The listed exceptions are caught and converted to compilation diagnostics. /// Any other exception is considered an unexpected error in the implementation and is not caught. /// /// <see cref="Metadata"/> objects may cache information decoded from the PE image. /// Reusing <see cref="Metadata"/> instances across metadata references will result in better performance. /// /// The calling <see cref="Compilation"/> doesn't take ownership of the <see cref="Metadata"/> objects returned by this method. /// The implementation needs to retrieve the object from a provider that manages their lifetime (such as metadata cache). /// The <see cref="Metadata"/> object is kept alive by the <see cref="Compilation"/> that called <see cref="GetMetadataNoCopy"/> /// and by all compilations created from it via calls to With- factory methods on <see cref="Compilation"/>, /// other than <see cref="Compilation.WithReferences(MetadataReference[])"/> overloads. A compilation created using /// <see cref="Compilation.WithReferences(MetadataReference[])"/> will call to <see cref="GetMetadataNoCopy"/> again. /// </remarks> protected abstract Metadata GetMetadataImpl(); internal Metadata GetMetadataNoCopy() { return GetMetadataImpl(); } /// <summary> /// Returns a copy of the <see cref="Metadata"/> object this <see cref="PortableExecutableReference"/> /// contains. This copy does not need to be <see cref="IDisposable.Dispose"/>d. /// </summary> /// <exception cref="BadImageFormatException">If the PE image format is invalid.</exception> /// <exception cref="IOException">The metadata image content can't be read.</exception> /// <exception cref="FileNotFoundException">The metadata image is stored in a file that can't be found.</exception> public Metadata GetMetadata() { return GetMetadataNoCopy().Copy(); } /// <summary> /// Returns the <see cref="MetadataId"/> for this reference's <see cref="Metadata"/>. /// This will be equivalent to calling <see cref="GetMetadata()"/>.<see cref="Metadata.Id"/>, /// but can be done more efficiently. /// </summary> /// <exception cref="BadImageFormatException">If the PE image format is invalid.</exception> /// <exception cref="IOException">The metadata image content can't be read.</exception> /// <exception cref="FileNotFoundException">The metadata image is stored in a file that can't be found.</exception> public MetadataId GetMetadataId() { return GetMetadataNoCopy().Id; } internal static Diagnostic ExceptionToDiagnostic(Exception e, CommonMessageProvider messageProvider, Location location, string display, MetadataImageKind kind) { if (e is BadImageFormatException) { int errorCode = (kind == MetadataImageKind.Assembly) ? messageProvider.ERR_InvalidAssemblyMetadata : messageProvider.ERR_InvalidModuleMetadata; return messageProvider.CreateDiagnostic(errorCode, location, display, e.Message); } var fileNotFound = e as FileNotFoundException; if (fileNotFound != null) { return messageProvider.CreateDiagnostic(messageProvider.ERR_MetadataFileNotFound, location, fileNotFound.FileName ?? string.Empty); } else { int errorCode = (kind == MetadataImageKind.Assembly) ? messageProvider.ERR_ErrorOpeningAssemblyFile : messageProvider.ERR_ErrorOpeningModuleFile; return messageProvider.CreateDiagnostic(errorCode, location, display, e.Message); } } } }