protected void GetCompilationReferences( TCompilation compilation, DiagnosticBag diagnostics, out ImmutableArray <MetadataReference> references, out IDictionary <ValueTuple <string, 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(ValueTuple.Create(referenceDirective.Location.SourceTree.FilePath, 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 <ValueTuple <string, string>, MetadataReference>(); referenceDirectiveLocationsBuilder = ArrayBuilder <Location> .GetInstance(); } referencesBuilder.Add(boundReference); referenceDirectiveLocationsBuilder.Add(referenceDirective.Location); boundReferenceDirectives.Add(ValueTuple.Create(referenceDirective.Location.SourceTree.FilePath, referenceDirective.File), boundReference); } // add external reference at the end, so that they are processed first: referencesBuilder.AddRange(compilation.ExternalReferences); // Add all explicit references of the previous script compilation. var previousScriptCompilation = compilation.ScriptCompilationInfo?.PreviousScriptCompilation; if (previousScriptCompilation != null) { referencesBuilder.AddRange(previousScriptCompilation.GetBoundReferenceManager().ExplicitReferences); } if (boundReferenceDirectives == null) { // no directive references resolved successfully: boundReferenceDirectives = SpecializedCollections.EmptyDictionary <ValueTuple <string, string>, MetadataReference>(); } references = referencesBuilder.ToImmutable(); referenceDirectiveLocations = referenceDirectiveLocationsBuilder?.ToImmutableAndFree() ?? ImmutableArray <Location> .Empty; } 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 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 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); 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)); }
/// <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); } }
public static ImmutableArray <T> ToImmutableOrEmptyAndFree <T>(this ArrayBuilder <T>?builder) { return(builder?.ToImmutableAndFree() ?? ImmutableArray <T> .Empty); }
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 || compilation.Options.MetadataReferenceProvider == 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); } // Workaround for bug #797360: include facades if we reference a Portable Library: referencesBuilder.AddRange(ResolveFacadeReferences(compilation)); // 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> /// Get the import strings for a given method, following forward pointers as necessary. /// </summary> /// <returns> /// For each namespace enclosing the method, a list of import strings, innermost to outermost. /// There should always be at least one entry, for the global namespace. /// </returns> public static ImmutableArray <ImmutableArray <string> > GetCSharpGroupedImportStrings(this ISymUnmanagedReader reader, int methodToken, int methodVersion, out ImmutableArray <string> externAliasStrings) { externAliasStrings = default(ImmutableArray <string>); ImmutableArray <short> groupSizes = default(ImmutableArray <short>); bool seenForward = false; RETRY: byte[] bytes = reader.GetCustomDebugInfoBytes(methodToken, methodVersion); if (bytes == null) { return(default(ImmutableArray <ImmutableArray <string> >)); } foreach (var record in GetCustomDebugInfoRecords(bytes)) { switch (record.Kind) { case CustomDebugInfoKind.UsingInfo: if (!groupSizes.IsDefault) { throw new InvalidOperationException(string.Format("Expected at most one Using record for method {0}", FormatMethodToken(methodToken))); } groupSizes = DecodeUsingRecord(record.Data); break; case CustomDebugInfoKind.ForwardInfo: if (!externAliasStrings.IsDefault) { throw new InvalidOperationException(string.Format("Did not expect both Forward and ForwardToModule records for method {0}", FormatMethodToken(methodToken))); } methodToken = DecodeForwardRecord(record.Data); // Follow at most one forward link (as in FUNCBRECEE::ensureNamespaces). // NOTE: Dev11 may produce chains of forward links (e.g. for System.Collections.Immutable). if (!seenForward) { seenForward = true; goto RETRY; } break; case CustomDebugInfoKind.ForwardToModuleInfo: if (!externAliasStrings.IsDefault) { throw new InvalidOperationException(string.Format("Expected at most one ForwardToModule record for method {0}", FormatMethodToken(methodToken))); } int moduleInfoMethodToken = DecodeForwardToModuleRecord(record.Data); ImmutableArray <string> allModuleInfoImportStrings = reader.GetMethodByVersion(moduleInfoMethodToken, methodVersion).GetImportStrings(); ArrayBuilder <string> externAliasBuilder = ArrayBuilder <string> .GetInstance(); foreach (string importString in allModuleInfoImportStrings) { if (IsCSharpExternAliasInfo(importString)) { externAliasBuilder.Add(importString); } } externAliasStrings = externAliasBuilder.ToImmutableAndFree(); break; } } if (groupSizes.IsDefault) { // This can happen in malformed PDBs (e.g. chains of forwards). return(default(ImmutableArray <ImmutableArray <string> >)); } var method = reader.GetMethodByVersion(methodToken, methodVersion); if (method == null) { return(default(ImmutableArray <ImmutableArray <string> >)); } ImmutableArray <string> importStrings = method.GetImportStrings(); int numImportStrings = importStrings.Length; ArrayBuilder <ImmutableArray <string> > resultBuilder = ArrayBuilder <ImmutableArray <string> > .GetInstance(groupSizes.Length); ArrayBuilder <string> groupBuilder = ArrayBuilder <string> .GetInstance(); int pos = 0; foreach (short groupSize in groupSizes) { for (int i = 0; i < groupSize; i++, pos++) { if (pos >= numImportStrings) { throw new InvalidOperationException(string.Format("Group size indicates more imports than there are import strings (method {0}).", FormatMethodToken(methodToken))); } string importString = importStrings[pos]; if (IsCSharpExternAliasInfo(importString)) { throw new InvalidOperationException(string.Format("Encountered extern alias info before all import strings were consumed (method {0}).", FormatMethodToken(methodToken))); } groupBuilder.Add(importString); } resultBuilder.Add(groupBuilder.ToImmutable()); groupBuilder.Clear(); } if (externAliasStrings.IsDefault) { Debug.Assert(groupBuilder.Count == 0); // Extern alias detail strings (prefix "Z") are not included in the group counts. for (; pos < numImportStrings; pos++) { string importString = importStrings[pos]; if (!IsCSharpExternAliasInfo(importString)) { throw new InvalidOperationException(string.Format("Expected only extern alias info strings after consuming the indicated number of imports (method {0}).", FormatMethodToken(methodToken))); } groupBuilder.Add(importString); } externAliasStrings = groupBuilder.ToImmutableAndFree(); } else { groupBuilder.Free(); if (pos < numImportStrings) { throw new InvalidOperationException(string.Format("Group size indicates fewer imports than there are import strings (method {0}).", FormatMethodToken(methodToken))); } } return(resultBuilder.ToImmutableAndFree()); }
internal ImmutableArray <GeneratedSourceText> ToImmutableAndFree() => _sourcesAdded.ToImmutableAndFree();
// Expects correct arguments. internal CompilationOptions( OutputKind outputKind, bool reportSuppressedDiagnostics, string moduleName, string mainTypeName, string scriptClassName, string cryptoKeyContainer, string cryptoKeyFile, ImmutableArray <byte> cryptoPublicKey, bool?delaySign, bool publicSign, OptimizationLevel optimizationLevel, bool checkOverflow, Platform platform, ReportDiagnostic generalDiagnosticOption, int warningLevel, ImmutableDictionary <string, ReportDiagnostic> specificDiagnosticOptions, bool concurrentBuild, bool deterministic, DateTime currentLocalTime, bool debugPlusMode, XmlReferenceResolver xmlReferenceResolver, SourceReferenceResolver sourceReferenceResolver, MetadataReferenceResolver metadataReferenceResolver, AssemblyIdentityComparer assemblyIdentityComparer, StrongNameProvider strongNameProvider, MetadataImportOptions metadataImportOptions, bool referencesSupersedeLowerVersions) { this.OutputKind = outputKind; this.ModuleName = moduleName; this.MainTypeName = mainTypeName; this.ScriptClassName = scriptClassName ?? WellKnownMemberNames.DefaultScriptClassName; this.CryptoKeyContainer = cryptoKeyContainer; this.CryptoKeyFile = cryptoKeyFile; this.CryptoPublicKey = cryptoPublicKey.NullToEmpty(); this.DelaySign = delaySign; this.CheckOverflow = checkOverflow; this.Platform = platform; this.GeneralDiagnosticOption = generalDiagnosticOption; this.WarningLevel = warningLevel; this.SpecificDiagnosticOptions = specificDiagnosticOptions; this.ReportSuppressedDiagnostics = reportSuppressedDiagnostics; this.OptimizationLevel = optimizationLevel; this.ConcurrentBuild = concurrentBuild; this.Deterministic = deterministic; this.CurrentLocalTime = currentLocalTime; this.DebugPlusMode = debugPlusMode; this.XmlReferenceResolver = xmlReferenceResolver; this.SourceReferenceResolver = sourceReferenceResolver; this.MetadataReferenceResolver = metadataReferenceResolver; this.StrongNameProvider = strongNameProvider; this.AssemblyIdentityComparer = assemblyIdentityComparer ?? AssemblyIdentityComparer.Default; this.MetadataImportOptions = metadataImportOptions; this.ReferencesSupersedeLowerVersions = referencesSupersedeLowerVersions; this.PublicSign = publicSign; _lazyErrors = new Lazy <ImmutableArray <Diagnostic> >(() => { ArrayBuilder <Diagnostic> builder = ArrayBuilder <Diagnostic> .GetInstance(); ValidateOptions(builder); return(builder.ToImmutableAndFree()); }); }