/// <summary> /// Create the stream which should be used for Emit. This should only be called one time. /// </summary> private Stream?CreateStream(DiagnosticBag diagnostics) { RoslynDebug.Assert(_stream == null); RoslynDebug.Assert(diagnostics != null); if (diagnostics.HasAnyErrors()) { return(null); } _stream = _emitStreamProvider.GetOrCreateStream(diagnostics); if (_stream == null) { return(null); } // If the current strong name provider is the Desktop version, signing can only be done to on-disk files. // If this binary is configured to be signed, create a temp file, output to that // then stream that to the stream that this method was called with. Otherwise output to the // stream that this method was called with. if (_emitStreamSignKind == EmitStreamSignKind.SignedWithFile) { RoslynDebug.Assert(_strongNameProvider != null); Stream tempStream; string tempFilePath; try { var fileSystem = _strongNameProvider.FileSystem; Func <string, Stream> streamConstructor = path => fileSystem.CreateFileStream( path, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite ); var tempDir = fileSystem.GetTempPath(); tempFilePath = Path.Combine(tempDir, Guid.NewGuid().ToString("N")); tempStream = FileUtilities.CreateFileStreamChecked( streamConstructor, tempFilePath ); } catch (IOException e) { throw new Cci.PeWritingException(e); } _tempInfo = (tempStream, tempFilePath); return(tempStream); } else { return(_stream); } }
internal AssemblyData ResolveMissingAssembly( AssemblyIdentity referenceIdentity, PortableExecutableReference peReference, MetadataImportOptions importOptions, DiagnosticBag diagnostics) { var metadata = GetMetadata(peReference, MessageProvider, Location.None, diagnostics); Debug.Assert(metadata != null || diagnostics.HasAnyErrors()); if (metadata == null) { return(null); } var assemblyMetadata = metadata as AssemblyMetadata; if (assemblyMetadata?.IsValidAssembly() != true) { diagnostics.Add(MessageProvider.CreateDiagnostic(MessageProvider.ERR_MetadataFileNotAssembly, Location.None, peReference.Display)); return(null); } var assembly = assemblyMetadata.GetAssembly(); // Allow reference and definition identities to differ in version, but not other properties: if (IdentityComparer.Compare(referenceIdentity, assembly.Identity) == AssemblyIdentityComparer.ComparisonResult.NotEquivalent) { return(null); } return(CreateAssemblyDataForFile( assembly, assemblyMetadata.CachedSymbols, peReference.DocumentationProvider, SimpleAssemblyName, importOptions, peReference.Properties.EmbedInteropTypes)); }
/// <summary> /// Resolves given metadata references to assemblies and modules. /// </summary> /// <param name="compilation">The compilation whose references are being resolved.</param> /// <param name="assemblyReferencesBySimpleName"> /// Used to filter out assemblies that have the same strong or weak identity. /// Maps simple name to a list of identities. The highest version of each name is the first. /// </param> /// <param name="references">List where to store resolved references. References from #r directives will follow references passed to the compilation constructor.</param> /// <param name="boundReferenceDirectiveMap">Maps #r values to successfully resolved metadata references. Does not contain values that failed to resolve.</param> /// <param name="boundReferenceDirectives">Unique metadata references resolved from #r directives.</param> /// <param name="assemblies">List where to store information about resolved assemblies to.</param> /// <param name="modules">List where to store information about resolved modules to.</param> /// <param name="diagnostics">Diagnostic bag where to report resolution errors.</param> /// <returns> /// Maps index to <paramref name="references"/> to an index of a resolved assembly or module in <paramref name="assemblies"/> or <paramref name="modules"/>, respectively. ///</returns> protected ImmutableArray <ResolvedReference> ResolveMetadataReferences( TCompilation compilation, [Out] Dictionary <string, List <ReferencedAssemblyIdentity> > assemblyReferencesBySimpleName, out ImmutableArray <MetadataReference> references, out IDictionary <ValueTuple <string, string>, MetadataReference> boundReferenceDirectiveMap, out ImmutableArray <MetadataReference> boundReferenceDirectives, out ImmutableArray <AssemblyData> assemblies, out ImmutableArray <PEModule> modules, DiagnosticBag diagnostics) { // Locations of all #r directives in the order they are listed in the references list. ImmutableArray <Location> referenceDirectiveLocations; GetCompilationReferences(compilation, diagnostics, out references, out boundReferenceDirectiveMap, out referenceDirectiveLocations); // References originating from #r directives precede references supplied as arguments of the compilation. int referenceCount = references.Length; int referenceDirectiveCount = (referenceDirectiveLocations != null ? referenceDirectiveLocations.Length : 0); var referenceMap = new ResolvedReference[referenceCount]; // Maps references that were added to the reference set (i.e. not filtered out as duplicates) to a set of names that // can be used to alias these references. Duplicate assemblies contribute their aliases into this set. Dictionary <MetadataReference, MergedAliases> lazyAliasMap = null; // Used to filter out duplicate references that reference the same file (resolve to the same full normalized path). var boundReferences = new Dictionary <MetadataReference, MetadataReference>(MetadataReferenceEqualityComparer.Instance); ArrayBuilder <MetadataReference> uniqueDirectiveReferences = (referenceDirectiveLocations != null) ? ArrayBuilder <MetadataReference> .GetInstance() : null; var assembliesBuilder = ArrayBuilder <AssemblyData> .GetInstance(); ArrayBuilder <PEModule> lazyModulesBuilder = null; bool supersedeLowerVersions = compilation.Options.ReferencesSupersedeLowerVersions; // When duplicate references with conflicting EmbedInteropTypes flag are encountered, // VB uses the flag from the last one, C# reports an error. We need to enumerate in reverse order // so that we find the one that matters first. for (int referenceIndex = referenceCount - 1; referenceIndex >= 0; referenceIndex--) { var boundReference = references[referenceIndex]; if (boundReference == null) { continue; } // add bound reference if it doesn't exist yet, merging aliases: MetadataReference existingReference; if (boundReferences.TryGetValue(boundReference, out existingReference)) { // merge properties of compilation-based references if the underlying compilations are the same if ((object)boundReference != existingReference) { MergeReferenceProperties(existingReference, boundReference, diagnostics, ref lazyAliasMap); } continue; } boundReferences.Add(boundReference, boundReference); Location location; if (referenceIndex < referenceDirectiveCount) { location = referenceDirectiveLocations[referenceIndex]; uniqueDirectiveReferences.Add(boundReference); } else { location = Location.None; } // compilation reference var compilationReference = boundReference as CompilationReference; if (compilationReference != null) { switch (compilationReference.Properties.Kind) { case MetadataImageKind.Assembly: existingReference = TryAddAssembly( compilationReference.Compilation.Assembly.Identity, boundReference, -assembliesBuilder.Count - 1, diagnostics, location, assemblyReferencesBySimpleName, supersedeLowerVersions); if (existingReference != null) { MergeReferenceProperties(existingReference, boundReference, diagnostics, ref lazyAliasMap); continue; } // Note, if SourceAssemblySymbol hasn't been created for // compilationAssembly.Compilation yet, we want this to happen // right now. Conveniently, this constructor will trigger creation of the // SourceAssemblySymbol. var asmData = CreateAssemblyDataForCompilation(compilationReference); AddAssembly(asmData, referenceIndex, referenceMap, assembliesBuilder); break; default: throw ExceptionUtilities.UnexpectedValue(compilationReference.Properties.Kind); } continue; } // PE reference var peReference = (PortableExecutableReference)boundReference; Metadata metadata = GetMetadata(peReference, MessageProvider, location, diagnostics); Debug.Assert(metadata != null || diagnostics.HasAnyErrors()); if (metadata != null) { Debug.Assert(metadata != null); switch (peReference.Properties.Kind) { case MetadataImageKind.Assembly: var assemblyMetadata = (AssemblyMetadata)metadata; WeakList <IAssemblySymbol> cachedSymbols = assemblyMetadata.CachedSymbols; if (assemblyMetadata.IsValidAssembly()) { PEAssembly assembly = assemblyMetadata.GetAssembly(); existingReference = TryAddAssembly( assembly.Identity, peReference, -assembliesBuilder.Count - 1, diagnostics, location, assemblyReferencesBySimpleName, supersedeLowerVersions); if (existingReference != null) { MergeReferenceProperties(existingReference, boundReference, diagnostics, ref lazyAliasMap); continue; } var asmData = CreateAssemblyDataForFile( assembly, cachedSymbols, peReference.DocumentationProvider, SimpleAssemblyName, compilation.Options.MetadataImportOptions, peReference.Properties.EmbedInteropTypes); AddAssembly(asmData, referenceIndex, referenceMap, assembliesBuilder); } else { diagnostics.Add(MessageProvider.CreateDiagnostic(MessageProvider.ERR_MetadataFileNotAssembly, location, peReference.Display)); } // asmData keeps strong ref after this point GC.KeepAlive(assemblyMetadata); break; case MetadataImageKind.Module: var moduleMetadata = (ModuleMetadata)metadata; if (moduleMetadata.Module.IsLinkedModule) { // We don't support netmodules since some checks in the compiler need information from the full PE image // (Machine, Bit32Required, PE image hash). if (!moduleMetadata.Module.IsEntireImageAvailable) { diagnostics.Add(MessageProvider.CreateDiagnostic(MessageProvider.ERR_LinkedNetmoduleMetadataMustProvideFullPEImage, location, peReference.Display)); } AddModule(moduleMetadata.Module, referenceIndex, referenceMap, ref lazyModulesBuilder); } else { diagnostics.Add(MessageProvider.CreateDiagnostic(MessageProvider.ERR_MetadataFileNotModule, location, peReference.Display)); } break; default: throw ExceptionUtilities.UnexpectedValue(peReference.Properties.Kind); } } } if (uniqueDirectiveReferences != null) { uniqueDirectiveReferences.ReverseContents(); boundReferenceDirectives = uniqueDirectiveReferences.ToImmutableAndFree(); } else { boundReferenceDirectives = ImmutableArray <MetadataReference> .Empty; } // We enumerated references in reverse order in the above code // and thus assemblies and modules in the builders are reversed. // Fix up all the indices and reverse the builder content now to get // the ordering matching the references. // // Also fills in aliases. for (int i = 0; i < referenceMap.Length; i++) { if (!referenceMap[i].IsSkipped) { int count = (referenceMap[i].Kind == MetadataImageKind.Assembly) ? assembliesBuilder.Count : lazyModulesBuilder?.Count ?? 0; int reversedIndex = count - 1 - referenceMap[i].Index; referenceMap[i] = GetResolvedReferenceAndFreePropertyMapEntry(references[i], reversedIndex, referenceMap[i].Kind, lazyAliasMap); } } assembliesBuilder.ReverseContents(); assemblies = assembliesBuilder.ToImmutableAndFree(); if (lazyModulesBuilder == null) { modules = ImmutableArray <PEModule> .Empty; } else { lazyModulesBuilder.ReverseContents(); modules = lazyModulesBuilder.ToImmutableAndFree(); } return(ImmutableArray.CreateRange(referenceMap)); }
internal bool HasAnyErrors() { Debug.Assert(DiagnosticBag is object); return(DiagnosticBag?.HasAnyErrors() == true); }