/
PortableExecutableReference.cs
206 lines (184 loc) · 9.45 KB
/
PortableExecutableReference.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// 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);
}
}
}
}