/// <summary> /// Creates a new immutable array based on filtered elements by the predicate. The array must not be null. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="array">The array to process</param> /// <param name="predicate">The delegate that defines the conditions of the element to search for.</param> /// <returns></returns> public static ImmutableArray <T> WhereAsArray <T>(this ImmutableArray <T> array, Func <T, bool> predicate) { Debug.Assert(!array.IsDefault); ArrayBuilder <T> builder = null; bool none = true; bool all = true; int n = array.Length; for (int i = 0; i < n; i++) { var a = array[i]; if (predicate(a)) { none = false; if (all) { continue; } Debug.Assert(i > 0); if (builder == null) { builder = ArrayBuilder <T> .GetInstance(); } builder.Add(a); } else { if (none) { all = false; continue; } Debug.Assert(i > 0); if (all) { Debug.Assert(builder == null); all = false; builder = ArrayBuilder <T> .GetInstance(); for (int j = 0; j < i; j++) { builder.Add(array[j]); } } } } if (builder != null) { Debug.Assert(!all); Debug.Assert(!none); return(builder.ToImmutableAndFree()); } else if (all) { return(array); } else { Debug.Assert(none); return(ImmutableArray <T> .Empty); } }
private AssemblyMetadata CreateAssemblyMetadata(ShadowCopy manifestModuleCopy) { // We don't need to use the global metadata cache here since the shadow copy // won't change and is private to us - only users of the same shadow copy provider see it. ArrayBuilder <ModuleMetadata> moduleBuilder = null; bool fault = true; ModuleMetadata manifestModule = null; try { manifestModule = CreateModuleMetadata(manifestModuleCopy); string originalDirectory = null, shadowCopyDirectory = null; foreach (string moduleName in manifestModule.GetModuleNames()) { if (moduleBuilder == null) { moduleBuilder = ArrayBuilder <ModuleMetadata> .GetInstance(); moduleBuilder.Add(manifestModule); originalDirectory = Path.GetDirectoryName(manifestModuleCopy.OriginalPath); shadowCopyDirectory = Path.GetDirectoryName(manifestModuleCopy.FullPath); } string originalPath = Path.Combine(originalDirectory, moduleName); string shadowCopyPath = Path.Combine(shadowCopyDirectory, moduleName); var moduleCopy = CopyFile(originalPath, shadowCopyPath); moduleBuilder.Add(CreateModuleMetadata(moduleCopy)); } var modules = (moduleBuilder != null) ? moduleBuilder.ToImmutable() : ImmutableArray.Create(manifestModule); fault = false; return(new AssemblyMetadata(modules)); } finally { if (fault) { if (manifestModule != null) { manifestModule.Dispose(); } if (moduleBuilder != null) { for (int i = 1; i < moduleBuilder.Count; i++) { moduleBuilder[i].Dispose(); } } } if (moduleBuilder != null) { moduleBuilder.Free(); } } }
protected void GetCompilationReferences( TCompilation compilation, DiagnosticBag diagnostics, out ImmutableArray <MetadataReference> references, out IDictionary <string, MetadataReference> boundReferenceDirectives, out ImmutableArray <Location> referenceDirectiveLocations) { boundReferenceDirectives = null; ArrayBuilder <MetadataReference> referencesBuilder = ArrayBuilder <MetadataReference> .GetInstance(); ArrayBuilder <Location> referenceDirectiveLocationsBuilder = null; try { foreach (var referenceDirective in compilation.ReferenceDirectives) { if (compilation.Options.MetadataReferenceResolver == null) { diagnostics.Add(MessageProvider.CreateDiagnostic(MessageProvider.ERR_MetadataReferencesNotSupported, referenceDirective.Location)); break; } // we already successfully bound #r with the same value: if (boundReferenceDirectives != null && boundReferenceDirectives.ContainsKey(referenceDirective.File)) { continue; } MetadataReference boundReference = ResolveReferenceDirective(referenceDirective.File, referenceDirective.Location, compilation); if (boundReference == null) { diagnostics.Add(MessageProvider.CreateDiagnostic(MessageProvider.ERR_MetadataFileNotFound, referenceDirective.Location, referenceDirective.File)); continue; } if (boundReferenceDirectives == null) { boundReferenceDirectives = new Dictionary <string, MetadataReference>(); referenceDirectiveLocationsBuilder = ArrayBuilder <Location> .GetInstance(); } referencesBuilder.Add(boundReference); referenceDirectiveLocationsBuilder.Add(referenceDirective.Location); boundReferenceDirectives.Add(referenceDirective.File, boundReference); } // add external reference at the end, so that they are processed first: referencesBuilder.AddRange(compilation.ExternalReferences); if (boundReferenceDirectives == null) { // no directive references resolved successfully: boundReferenceDirectives = SpecializedCollections.EmptyDictionary <string, MetadataReference>(); } references = referencesBuilder.ToImmutable(); referenceDirectiveLocations = referenceDirectiveLocationsBuilder == null ? ImmutableArray <Location> .Empty : referenceDirectiveLocationsBuilder.ToImmutableAndFree(); } finally { // Put this in a finally because we have tests that (intentionally) cause ResolveReferenceDirective to throw and // we don't want to clutter the test output with leak reports. referencesBuilder.Free(); } }
/// <summary> /// Resolves given metadata references to assemblies and modules. /// </summary> /// <param name="compilation">The compilation whose references are being resolved.</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 successuflly 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 ImmutableArray <MetadataReference> references, out IDictionary <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); int externalReferenceCount = referenceCount - referenceDirectiveCount; 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, ArrayBuilder <string> > aliasMap = 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); // Used to filter out assemblies that have the same strong or weak identity. // Maps simple name to a list of full names. Dictionary <string, List <ReferencedAssemblyIdentity> > assemblyReferencesBySimpleName = null; ArrayBuilder <MetadataReference> uniqueDirectiveReferences = (referenceDirectiveLocations != null) ? ArrayBuilder <MetadataReference> .GetInstance() : null; ArrayBuilder <AssemblyData> assembliesBuilder = null; ArrayBuilder <PEModule> modulesBuilder = null; // 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 aliasMap); } 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, diagnostics, location, ref assemblyReferencesBySimpleName); if (existingReference != null) { MergeReferenceProperties(existingReference, boundReference, diagnostics, ref aliasMap); 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, ref 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, diagnostics, location, ref assemblyReferencesBySimpleName); if (existingReference != null) { MergeReferenceProperties(existingReference, boundReference, diagnostics, ref aliasMap); continue; } var asmData = CreateAssemblyDataForFile( assembly, cachedSymbols, peReference.DocumentationProvider, SimpleAssemblyName, compilation.Options.MetadataImportOptions, peReference.Properties.EmbedInteropTypes); AddAssembly(asmData, referenceIndex, referenceMap, ref 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 modulesBuilder); } 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; } for (int i = 0; i < referenceMap.Length; i++) { if (!referenceMap[i].IsSkipped) { int count = referenceMap[i].Kind == MetadataImageKind.Assembly ? ((object)assembliesBuilder == null ? 0 : assembliesBuilder.Count) : ((object)modulesBuilder == null ? 0 : modulesBuilder.Count); int reversedIndex = count - 1 - referenceMap[i].Index; referenceMap[i] = new ResolvedReference(reversedIndex, referenceMap[i].Kind, GetAliases(references[i], aliasMap)); } } if (assembliesBuilder == null) { assemblies = ImmutableArray <AssemblyData> .Empty; } else { assembliesBuilder.ReverseContents(); assemblies = assembliesBuilder.ToImmutableAndFree(); } if (modulesBuilder == null) { modules = ImmutableArray <PEModule> .Empty; } else { modulesBuilder.ReverseContents(); modules = modulesBuilder.ToImmutableAndFree(); } return(ImmutableArray.CreateRange(referenceMap)); }
public void RegisterPostInitializationOutput(Action <IncrementalGeneratorPostInitializationContext> callback) => _outputNodes.Add(new PostInitOutputNode(callback.WrapUserAction()));
/// <summary> /// Adds a <see cref="SourceText"/> to the compilation /// </summary> /// <param name="hintName">An identifier that can be used to reference this source text, must be unique within this generator</param> /// <param name="sourceText">The <see cref="SourceText"/> to add to the compilation</param> public void AddSource(string hintName, SourceText sourceText) => Sources.Add(new GeneratedSourceText(hintName, sourceText));
/// <remarks> /// Caller is responsible for freeing any allocated ArrayBuilders. /// </remarks> private static void AddAssembly(AssemblyData data, int referenceIndex, ResolvedReference[] referenceMap, ArrayBuilder <AssemblyData> assemblies) { // aliases will be filled in later: referenceMap[referenceIndex] = new ResolvedReference(assemblies.Count, MetadataImageKind.Assembly); assemblies.Add(data); }