/// <summary> /// Performs validation of options compatibilities and generates diagnostics if needed /// </summary> protected abstract void ValidateOptions(ArrayBuilder <Diagnostic> builder);
/// <summary> /// For the given set of AssemblyData objects, do the following: /// 1) Resolve references from each assembly against other assemblies in the set. /// 2) Choose suitable AssemblySymbol instance for each AssemblyData object. /// /// The first element (index==0) of the assemblies array represents the assembly being built. /// One can think about the rest of the items in assemblies array as assembly references given to the compiler to /// build executable for the assembly being built. /// </summary> /// /// <param name="explicitAssemblies"> /// An array of <see cref="AssemblyData"/> objects describing assemblies, for which this method should /// resolve references and find suitable AssemblySymbols. The first slot contains the assembly being built. /// </param> /// <param name="resolverOpt"> /// Reference resolver used to look up missing assemblies. /// </param> /// <param name="importOptions"> /// Import options applied to implicitly resolved references. /// </param> /// <param name="allAssemblies"> /// Updated array <paramref name="explicitAssemblies"/> with resolved implicitly referenced assemblies appended. /// </param> /// <param name="implicitlyResolvedReferences"> /// Implicitly resolved references. /// </param> /// <param name="implicitlyResolvedReferenceMap"> /// Maps indices of implicitly resolved references to the corresponding indices of resolved assemblies in <paramref name="allAssemblies"/> (explicit + implicit). /// </param> /// <param name="resolutionDiagnostics"> /// Any diagnostics reported while resolving missing assemblies. /// </param> /// <param name="hasCircularReference"> /// True if the assembly being compiled is indirectly referenced through some of its own references. /// </param> /// <param name="corLibraryIndex"> /// The definition index of the COR library. /// </param> /// <return> /// An array of <see cref="BoundInputAssembly"/> structures describing the result. It has the same amount of items as /// the input assemblies array, <see cref="BoundInputAssembly"/> for each input AssemblyData object resides /// at the same position. /// /// Each <see cref="BoundInputAssembly"/> contains the following data: /// /// - Suitable AssemblySymbol instance for the corresponding assembly, /// null reference if none is available/found. Always null for the first element, which corresponds to the assembly being built. /// /// - Result of resolving assembly references of the corresponding assembly /// against provided set of assembly definitions. Essentially, this is an array returned by /// <see cref="AssemblyData.BindAssemblyReferences(ImmutableArray{AssemblyData}, AssemblyIdentityComparer)"/> method. /// </return> protected BoundInputAssembly[] Bind( ImmutableArray <AssemblyData> explicitAssemblies, MetadataReferenceResolver resolverOpt, MetadataImportOptions importOptions, out ImmutableArray <AssemblyData> allAssemblies, out ImmutableArray <MetadataReference> implicitlyResolvedReferences, out ImmutableArray <ResolvedReference> implicitlyResolvedReferenceMap, DiagnosticBag resolutionDiagnostics, out bool hasCircularReference, out int corLibraryIndex) { Debug.Assert(explicitAssemblies[0] is AssemblyDataForAssemblyBeingBuilt); var referenceBindings = ArrayBuilder <AssemblyReferenceBinding[]> .GetInstance(); try { // Based on assembly identity, for each assembly, // bind its references against the other assemblies we have. for (int i = 0; i < explicitAssemblies.Length; i++) { referenceBindings.Add(explicitAssemblies[i].BindAssemblyReferences(explicitAssemblies, IdentityComparer)); } if (resolverOpt?.ResolveMissingAssemblies == true) { ResolveAndBindMissingAssemblies(explicitAssemblies, resolverOpt, importOptions, referenceBindings, out allAssemblies, out implicitlyResolvedReferences, out implicitlyResolvedReferenceMap, resolutionDiagnostics); } else { allAssemblies = explicitAssemblies; implicitlyResolvedReferences = ImmutableArray <MetadataReference> .Empty; implicitlyResolvedReferenceMap = ImmutableArray <ResolvedReference> .Empty; } // implicitly resolved missing assemblies were added to both referenceBindings and assemblies: Debug.Assert(referenceBindings.Count == allAssemblies.Length); hasCircularReference = CheckCircularReference(referenceBindings); corLibraryIndex = IndexOfCorLibrary(allAssemblies); // For each assembly, locate AssemblySymbol with similar reference resolution // What does similar mean? // Similar means: // 1) The same references are resolved against the assemblies that we are given // (or were found duiring implicit assembly resolution). // 2) The same assembly is used as the COR library. var boundInputs = new BoundInputAssembly[referenceBindings.Count]; for (int i = 0; i < referenceBindings.Count; i++) { boundInputs[i].ReferenceBinding = referenceBindings[i]; } var candidateInputAssemblySymbols = new TAssemblySymbol[allAssemblies.Length]; // If any assembly from assemblies array refers back to assemblyBeingBuilt, // we know that we cannot reuse symbols for any assemblies containing NoPia // local types. Because we cannot reuse symbols for assembly referring back // to assemblyBeingBuilt. if (!hasCircularReference) { // Deal with assemblies containing NoPia local types. if (ReuseAssemblySymbolsWithNoPiaLocalTypes(boundInputs, candidateInputAssemblySymbols, allAssemblies, corLibraryIndex)) { return(boundInputs); } } // NoPia shortcut either didn't apply or failed, go through general process // of matching candidates. ReuseAssemblySymbols(boundInputs, candidateInputAssemblySymbols, allAssemblies, corLibraryIndex); return(boundInputs); } finally { referenceBindings.Free(); } }
// 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 = string.IsNullOrEmpty(cryptoKeyFile) ? null : 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> >(() => { var builder = ArrayBuilder <Diagnostic> .GetInstance(); ValidateOptions(builder); return(builder.ToImmutableAndFree()); }); }
public AnalyzerConfigOptionsResult GetOptionsForSourcePath(string sourcePath) { if (sourcePath == null) { throw new ArgumentNullException(nameof(sourcePath)); } var treeOptionsBuilder = _treeOptionsPool.Allocate(); var analyzerOptionsBuilder = _analyzerOptionsPool.Allocate(); var diagnosticBuilder = ArrayBuilder <Diagnostic> .GetInstance(); var sectionKey = _sectionKeyPool.Allocate(); var normalizedPath = PathUtilities.NormalizeWithForwardSlash(sourcePath); // The editorconfig paths are sorted from shortest to longest, so matches // are resolved from most nested to least nested, where last setting wins for (int analyzerConfigIndex = 0; analyzerConfigIndex < _analyzerConfigs.Length; analyzerConfigIndex++) { var config = _analyzerConfigs[analyzerConfigIndex]; if (normalizedPath.StartsWith(config.NormalizedDirectory, StringComparison.Ordinal)) { // If this config is a root config, then clear earlier options since they don't apply // to this source file. if (config.IsRoot) { analyzerOptionsBuilder.Clear(); treeOptionsBuilder.Clear(); diagnosticBuilder.Clear(); } int dirLength = config.NormalizedDirectory.Length; // Leave '/' if the normalized directory ends with a '/'. This can happen if // we're in a root directory (e.g. '/' or 'Z:/'). The section matching // always expects that the relative path start with a '/'. if (config.NormalizedDirectory[dirLength - 1] == '/') { dirLength--; } string relativePath = normalizedPath.Substring(dirLength); ImmutableArray <SectionNameMatcher?> matchers = _analyzerMatchers[analyzerConfigIndex]; for (int sectionIndex = 0; sectionIndex < matchers.Length; sectionIndex++) { if (matchers[sectionIndex]?.IsMatch(relativePath) == true) { var section = config.NamedSections[sectionIndex]; addOptions( section, treeOptionsBuilder, analyzerOptionsBuilder, diagnosticBuilder, config.PathToFile, _diagnosticIdCache); sectionKey.Add(section); } } } } // Try to avoid creating extra dictionaries if we've already seen an options result with the // exact same options if (!_optionsCache.TryGetValue(sectionKey, out var result)) { result = new AnalyzerConfigOptionsResult( treeOptionsBuilder.Count > 0 ? treeOptionsBuilder.ToImmutable() : SyntaxTree.EmptyDiagnosticOptions, analyzerOptionsBuilder.Count > 0 ? analyzerOptionsBuilder.ToImmutable() : AnalyzerConfigOptions.EmptyDictionary, diagnosticBuilder.ToImmutableAndFree()); if (_optionsCache.TryAdd(sectionKey, result)) { // Release the pooled object to be used as a key _sectionKeyPool.ForgetTrackedObject(sectionKey); } else { freeKey(sectionKey, _sectionKeyPool); } } else { freeKey(sectionKey, _sectionKeyPool); } treeOptionsBuilder.Clear(); analyzerOptionsBuilder.Clear(); _treeOptionsPool.Free(treeOptionsBuilder); _analyzerOptionsPool.Free(analyzerOptionsBuilder); return(result);
private static void UpdateBindingsOfAssemblyBeingBuilt(ArrayBuilder <AssemblyReferenceBinding[]> referenceBindings, int explicitAssemblyCount, ArrayBuilder <AssemblyData> implicitAssemblies) { var referenceBindingsOfAssemblyBeingBuilt = referenceBindings[0]; // add implicitly resolved assemblies to the bindings of the assembly being built: var bindingsOfAssemblyBeingBuilt = ArrayBuilder <AssemblyReferenceBinding> .GetInstance(referenceBindingsOfAssemblyBeingBuilt.Length + implicitAssemblies.Count); // add bindings for explicitly specified assemblies (-1 for the assembly being built): bindingsOfAssemblyBeingBuilt.AddRange(referenceBindingsOfAssemblyBeingBuilt, explicitAssemblyCount - 1); // add bindings for implicitly resolved assemblies: for (int i = 0; i < implicitAssemblies.Count; i++) { bindingsOfAssemblyBeingBuilt.Add(new AssemblyReferenceBinding(implicitAssemblies[i].Identity, explicitAssemblyCount + i)); } // add bindings for assemblies referenced by modules added to the compilation: bindingsOfAssemblyBeingBuilt.AddRange(referenceBindingsOfAssemblyBeingBuilt, explicitAssemblyCount - 1, referenceBindingsOfAssemblyBeingBuilt.Length - explicitAssemblyCount + 1); referenceBindings[0] = bindingsOfAssemblyBeingBuilt.ToArrayAndFree(); }
internal static void CheckAssemblyOrModuleName(string name, CommonMessageProvider messageProvider, int code, ArrayBuilder <Diagnostic> builder) { string errorArgumentResourceId = GetAssemblyOrModuleNameErrorArgumentResourceName(name); if (errorArgumentResourceId != null) { builder.Add( messageProvider.CreateDiagnostic(code, Location.None, new CodeAnalysisResourcesLocalizableErrorArgument(errorArgumentResourceId))); } }
public void AddRange(ArrayBuilder <T> items) { _builder.AddRange(items._builder); }
/// <summary> /// Takes a node and returns a set of declarations that overlap the node's span. /// </summary> internal abstract void ComputeDeclarationsInNode(SyntaxNode node, bool getSymbol, ArrayBuilder<DeclarationInfo> builder, CancellationToken cancellationToken, int? levelsToCompute = null);
internal void ResolveAnalyzersFromArguments( string language, List <DiagnosticInfo> diagnostics, CommonMessageProvider messageProvider, IAnalyzerAssemblyLoader analyzerLoader, bool skipAnalyzers, out ImmutableArray <DiagnosticAnalyzer> analyzers, out ImmutableArray <ISourceGenerator> generators) { var analyzerBuilder = ImmutableArray.CreateBuilder <DiagnosticAnalyzer>(); var generatorBuilder = ImmutableArray.CreateBuilder <ISourceGenerator>(); EventHandler <AnalyzerLoadFailureEventArgs> errorHandler = (o, e) => { var analyzerReference = o as AnalyzerFileReference; RoslynDebug.Assert(analyzerReference is object); DiagnosticInfo?diagnostic; switch (e.ErrorCode) { case AnalyzerLoadFailureEventArgs.FailureErrorCode.UnableToLoadAnalyzer: diagnostic = new DiagnosticInfo(messageProvider, messageProvider.WRN_UnableToLoadAnalyzer, analyzerReference.FullPath, e.Message); break; case AnalyzerLoadFailureEventArgs.FailureErrorCode.UnableToCreateAnalyzer: diagnostic = new DiagnosticInfo(messageProvider, messageProvider.WRN_AnalyzerCannotBeCreated, e.TypeName ?? "", analyzerReference.FullPath, e.Message); break; case AnalyzerLoadFailureEventArgs.FailureErrorCode.NoAnalyzers: diagnostic = new DiagnosticInfo(messageProvider, messageProvider.WRN_NoAnalyzerInAssembly, analyzerReference.FullPath); break; case AnalyzerLoadFailureEventArgs.FailureErrorCode.None: default: return; } // Filter this diagnostic based on the compilation options so that /nowarn and /warnaserror etc. take effect. diagnostic = messageProvider.FilterDiagnosticInfo(diagnostic, this.CompilationOptions); if (diagnostic != null) { diagnostics.Add(diagnostic); } }; var resolvedReferences = ArrayBuilder <AnalyzerFileReference> .GetInstance(); foreach (var reference in AnalyzerReferences) { var resolvedReference = ResolveAnalyzerReference(reference, analyzerLoader); if (resolvedReference != null) { resolvedReferences.Add(resolvedReference); // register the reference to the analyzer loader: analyzerLoader.AddDependencyLocation(resolvedReference.FullPath); } else { diagnostics.Add(new DiagnosticInfo(messageProvider, messageProvider.ERR_MetadataFileNotFound, reference.FilePath)); } } // All analyzer references are registered now, we can start loading them: foreach (var resolvedReference in resolvedReferences) { resolvedReference.AnalyzerLoadFailed += errorHandler; if (!skipAnalyzers) { resolvedReference.AddAnalyzers(analyzerBuilder, language); } resolvedReference.AddGenerators(generatorBuilder, language); resolvedReference.AnalyzerLoadFailed -= errorHandler; } resolvedReferences.Free(); generators = generatorBuilder.ToImmutable(); analyzers = analyzerBuilder.ToImmutable(); }
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> /// Gets the <see cref="DeclarationInfo"/> for all the declarations whose span overlaps with the given <paramref name="span"/>. /// </summary> /// <param name="span">Span to get declarations.</param> /// <param name="getSymbol">Flag indicating whether <see cref="DeclarationInfo.DeclaredSymbol"/> should be computed for the returned declaration infos. /// If false, then <see cref="DeclarationInfo.DeclaredSymbol"/> is always null.</param> /// <param name="builder">Builder to add declarations.</param> /// <param name="cancellationToken">Cancellation token.</param> internal abstract void ComputeDeclarationsInSpan(TextSpan span, bool getSymbol, ArrayBuilder<DeclarationInfo> builder, CancellationToken cancellationToken);
/// <remarks> /// Caller is responsible for freeing any allocated ArrayBuilders. /// </remarks> private static void AddModule(PEModule module, int referenceIndex, ResolvedReference[] referenceMap, ref ArrayBuilder <PEModule> modules) { if (modules == null) { modules = ArrayBuilder <PEModule> .GetInstance(); } referenceMap[referenceIndex] = new ResolvedReference(modules.Count, MetadataImageKind.Module); modules.Add(module); }
/// <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); }
/// <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.IsSubmission; // 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)); }
/// <summary> /// Decodes a type name. A type name is a string which is terminated by the end of the string or one of the /// delimiters '+', ',', '[', ']'. '+' separates nested classes. '[' and ']' /// enclosed generic type arguments. ',' separates types. /// </summary> internal AssemblyQualifiedTypeName DecodeTypeName(bool isTypeArgument = false, bool isTypeArgumentWithAssemblyName = false) { Debug.Assert(!isTypeArgumentWithAssemblyName || isTypeArgument); string topLevelType = null; ArrayBuilder <string> nestedTypesBuilder = null; AssemblyQualifiedTypeName[] typeArguments = null; int pointerCount = 0; ArrayBuilder <int> arrayRanksBuilder = null; string assemblyName = null; bool decodingTopLevelType = true; bool isGenericTypeName = false; var pooledStrBuilder = PooledStringBuilder.GetInstance(); StringBuilder typeNameBuilder = pooledStrBuilder.Builder; while (!EndOfInput) { int i = _input.IndexOfAny(s_typeNameDelimiters, _offset); if (i >= 0) { char c = _input[i]; // Found name, which could be a generic name with arity. // Generic type parameter count, if any, are handled in DecodeGenericName. string decodedString = DecodeGenericName(i); Debug.Assert(decodedString != null); // Type name is generic if the decoded name of the top level type OR any of the outer types of a nested type had the '`' character. isGenericTypeName = isGenericTypeName || decodedString.IndexOf(GenericTypeNameManglingChar) >= 0; typeNameBuilder.Append(decodedString); switch (c) { case '*': if (arrayRanksBuilder != null) { // Error case, array shape must be specified at the end of the type name. // Process as a regular character and continue. typeNameBuilder.Append(c); } else { pointerCount++; } Advance(); break; case '+': if (arrayRanksBuilder != null || pointerCount > 0) { // Error case, array shape must be specified at the end of the type name. // Process as a regular character and continue. typeNameBuilder.Append(c); } else { // Type followed by nested type. Handle nested class separator and collect the nested types. HandleDecodedTypeName(typeNameBuilder.ToString(), decodingTopLevelType, ref topLevelType, ref nestedTypesBuilder); typeNameBuilder.Clear(); decodingTopLevelType = false; } Advance(); break; case '[': // Is type followed by generic type arguments? if (isGenericTypeName && typeArguments == null) { Advance(); if (arrayRanksBuilder != null || pointerCount > 0) { // Error case, array shape must be specified at the end of the type name. // Process as a regular character and continue. typeNameBuilder.Append(c); } else { // Decode type arguments. typeArguments = DecodeTypeArguments(); } } else { // Decode array shape. DecodeArrayShape(typeNameBuilder, ref arrayRanksBuilder); } break; case ']': if (isTypeArgument) { // End of type arguments. This occurs when the last type argument is a type in the // current assembly. goto ExitDecodeTypeName; } else { // Error case, process as a regular character and continue. typeNameBuilder.Append(c); Advance(); break; } case ',': // A comma may separate a type name from its assembly name or a type argument from // another type argument. // If processing non-type argument or a type argument with assembly name, // process the characters after the comma as an assembly name. if (!isTypeArgument || isTypeArgumentWithAssemblyName) { Advance(); if (!EndOfInput && Char.IsWhiteSpace(Current)) { Advance(); } assemblyName = DecodeAssemblyName(isTypeArgumentWithAssemblyName); } goto ExitDecodeTypeName; default: throw ExceptionUtilities.UnexpectedValue(c); } } else { typeNameBuilder.Append(DecodeGenericName(_input.Length)); goto ExitDecodeTypeName; } } ExitDecodeTypeName: HandleDecodedTypeName(typeNameBuilder.ToString(), decodingTopLevelType, ref topLevelType, ref nestedTypesBuilder); pooledStrBuilder.Free(); return(new AssemblyQualifiedTypeName( topLevelType, nestedTypesBuilder?.ToArrayAndFree(), typeArguments, pointerCount, arrayRanksBuilder?.ToArrayAndFree(), assemblyName)); }
public ImmutableArray <DynamicAnalysisSpan> GetSpans(BlobHandle handle) { if (handle.IsNil) { return(ImmutableArray <DynamicAnalysisSpan> .Empty); } var builder = ArrayBuilder <DynamicAnalysisSpan> .GetInstance(); var reader = GetBlobReader(handle); // header: int documentRowId = ReadDocumentRowId(ref reader); int previousStartLine = -1; ushort previousStartColumn = 0; // records: while (reader.RemainingBytes > 0) { ReadDeltaLinesAndColumns(ref reader, out var deltaLines, out var deltaColumns); // document: if (deltaLines == 0 && deltaColumns == 0) { documentRowId = ReadDocumentRowId(ref reader); continue; } int startLine; ushort startColumn; // delta Start Line & Column: if (previousStartLine < 0) { Debug.Assert(previousStartColumn == 0); startLine = ReadLine(ref reader); startColumn = ReadColumn(ref reader); } else { startLine = AddLines(previousStartLine, reader.ReadCompressedSignedInteger()); startColumn = AddColumns( previousStartColumn, reader.ReadCompressedSignedInteger() ); } previousStartLine = startLine; previousStartColumn = startColumn; int endLine = AddLines(startLine, deltaLines); int endColumn = AddColumns(startColumn, deltaColumns); var linePositionSpan = new DynamicAnalysisSpan( documentRowId, startLine, startColumn, endLine, endColumn ); builder.Add(linePositionSpan); } return(builder.ToImmutableAndFree()); }
private static void HandleDecodedTypeName(string decodedTypeName, bool decodingTopLevelType, ref string topLevelType, ref ArrayBuilder <string> nestedTypesBuilder) { if (decodedTypeName.Length != 0) { if (decodingTopLevelType) { Debug.Assert(topLevelType == null); topLevelType = decodedTypeName; } else { if (nestedTypesBuilder == null) { nestedTypesBuilder = ArrayBuilder <string> .GetInstance(); } nestedTypesBuilder.Add(decodedTypeName); } } }
public DynamicAnalysisDataReader(byte *buffer, int size) { var reader = new BlobReader(buffer, size); // header: if ( reader.ReadByte() != 'D' || reader.ReadByte() != 'A' || reader.ReadByte() != 'M' || reader.ReadByte() != 'D' ) { throw new BadImageFormatException(); } // version byte major = reader.ReadByte(); byte minor = reader.ReadByte(); if (major != 0 || minor < 1 || minor > 2) { throw new NotSupportedException(); } // table sizes: int documentRowCount = reader.ReadInt32(); int methodSpanRowCount = reader.ReadInt32(); // blob heap sizes: int stringHeapSize = (minor == 1) ? reader.ReadInt32() : 0; int userStringHeapSize = (minor == 1) ? reader.ReadInt32() : 0; int guidHeapSize = reader.ReadInt32(); int blobHeapSize = reader.ReadInt32(); // TODO: check size ranges bool isBlobHeapSmall = blobHeapSize <= ushort.MaxValue; bool isGuidHeapSmall = guidHeapSize / GuidSize <= ushort.MaxValue; var documentsBuilder = ArrayBuilder <DynamicAnalysisDocument> .GetInstance( documentRowCount ); for (int i = 0; i < documentRowCount; i++) { var name = MetadataTokens.BlobHandle(ReadReference(ref reader, isBlobHeapSmall)); var hashAlgorithm = MetadataTokens.GuidHandle( ReadReference(ref reader, isGuidHeapSmall) ); var hash = MetadataTokens.BlobHandle(ReadReference(ref reader, isBlobHeapSmall)); documentsBuilder.Add(new DynamicAnalysisDocument(name, hashAlgorithm, hash)); } Documents = documentsBuilder.ToImmutableAndFree(); var methodsBuilder = ArrayBuilder <DynamicAnalysisMethod> .GetInstance( methodSpanRowCount ); for (int i = 0; i < methodSpanRowCount; i++) { methodsBuilder.Add( new DynamicAnalysisMethod( MetadataTokens.BlobHandle(ReadReference(ref reader, isBlobHeapSmall)) ) ); } Methods = methodsBuilder.ToImmutableAndFree(); int stringHeapOffset = reader.Offset; int userStringHeapOffset = stringHeapOffset + stringHeapSize; int guidHeapOffset = userStringHeapOffset + userStringHeapSize; int blobHeapOffset = guidHeapOffset + guidHeapSize; if (reader.Length != blobHeapOffset + blobHeapSize) { throw new BadImageFormatException(); } _guidHeapBlob = new Blob(buffer + guidHeapOffset, guidHeapSize); _blobHeapBlob = new Blob(buffer + blobHeapOffset, blobHeapSize); }
public DebuggerProxy(ArrayBuilder <T> builder) { _builder = builder; }
private void ResolveAndBindMissingAssemblies( ImmutableArray <AssemblyData> explicitAssemblies, MetadataReferenceResolver resolver, MetadataImportOptions importOptions, [In, Out] ArrayBuilder <AssemblyReferenceBinding[]> referenceBindings, out ImmutableArray <AssemblyData> allAssemblies, out ImmutableArray <MetadataReference> metadataReferences, out ImmutableArray <ResolvedReference> resolvedReferences, DiagnosticBag resolutionDiagnostics) { Debug.Assert(explicitAssemblies[0] is AssemblyDataForAssemblyBeingBuilt); var implicitAssemblies = ArrayBuilder <AssemblyData> .GetInstance(); // tracks identities we already asked the resolver to resolve: var requestedIdentities = PooledHashSet <AssemblyIdentity> .GetInstance(); // reference bindings of implicit assemblies, used to calculate a fixed point: var referenceBindingsToProcess = ArrayBuilder <AssemblyReferenceBinding[]> .GetInstance(); var metadataReferencesBuilder = ArrayBuilder <MetadataReference> .GetInstance(); Dictionary <string, List <ReferencedAssemblyIdentity> > lazyResolvedReferencesBySimpleName = null; Dictionary <MetadataReference, ArrayBuilder <string> > lazyAliasMap = null; try { // collect all missing identities, resolve the assemblies and bind their references against explicit definitions: referenceBindingsToProcess.AddRange(referenceBindings); while (referenceBindingsToProcess.Count > 0) { foreach (var binding in referenceBindingsToProcess.Pop()) { // only attempt to resolve unbound references (regardless of version difference of the bound ones) if (binding.IsBound) { continue; } if (!requestedIdentities.Add(binding.ReferenceIdentity)) { continue; } var peReference = resolver.ResolveMissingAssembly(binding.ReferenceIdentity); if (peReference == null) { continue; } var data = ResolveMissingAssembly(binding.ReferenceIdentity, peReference, importOptions, resolutionDiagnostics); if (data == null) { continue; } // The resolver may return different version than we asked for, so it may happen that // it returns the same identity for two different input identities (e.g. if a higher version // of an assembly is available than what the assemblies reference: "A, v1" -> "A, v3" and "A, v2" -> "A, v3"). // If such case occurs merge the properties (aliases) of the resulting references in the same way we do // during initial explicit references resolution. var existingReference = TryAddAssembly(data.Identity, peReference, resolutionDiagnostics, Location.None, ref lazyResolvedReferencesBySimpleName); if (existingReference != null) { MergeReferenceProperties(existingReference, peReference, resolutionDiagnostics, ref lazyAliasMap); continue; } metadataReferencesBuilder.Add(peReference); implicitAssemblies.Add(data); var referenceBinding = data.BindAssemblyReferences(explicitAssemblies, IdentityComparer); referenceBindings.Add(referenceBinding); referenceBindingsToProcess.Push(referenceBinding); } } if (implicitAssemblies.Count == 0) { Debug.Assert(lazyAliasMap == null); Debug.Assert(lazyResolvedReferencesBySimpleName == null); resolvedReferences = ImmutableArray <ResolvedReference> .Empty; metadataReferences = ImmutableArray <MetadataReference> .Empty; allAssemblies = explicitAssemblies; return; } // Rebind assembly references that were initially missing. All bindings established above // are against explicitly specified references. // NB: includes the assembly being built: int explicitAssemblyCount = explicitAssemblies.Length; allAssemblies = explicitAssemblies.AddRange(implicitAssemblies); for (int bindingsIndex = 0; bindingsIndex < referenceBindings.Count; bindingsIndex++) { var referenceBinding = referenceBindings[bindingsIndex]; for (int i = 0; i < referenceBinding.Length; i++) { var binding = referenceBinding[i]; // We don't rebind references bound to a non-matching version of a reference that was explicitly // specified, even if we have a better version now. if (binding.IsBound) { continue; } // We only need to resolve against implicitly resolved assemblies, // since we already resolved against explicitly specified ones. referenceBinding[i] = ResolveReferencedAssembly( binding.ReferenceIdentity, allAssemblies, explicitAssemblyCount, IdentityComparer); } } UpdateBindingsOfAssemblyBeingBuilt(referenceBindings, explicitAssemblyCount, implicitAssemblies); metadataReferences = metadataReferencesBuilder.ToImmutable(); resolvedReferences = ToResolvedAssemblyReferences(metadataReferences, lazyAliasMap, explicitAssemblyCount); } finally { implicitAssemblies.Free(); requestedIdentities.Free(); referenceBindingsToProcess.Free(); metadataReferencesBuilder.Free(); } }
public void AddRange <U>(ArrayBuilder <U> items) where U : T { _builder.AddRange(items._builder); }
private static async Task <ImmutableArray <TextChange> > AddDocumentMergeChangesAsync( Document oldDocument, Document newDocument, List <TextChange> cumulativeChanges, List <UnmergedDocumentChanges> unmergedChanges, LinkedFileGroupSessionInfo groupSessionInfo, IDocumentTextDifferencingService textDiffService, CancellationToken cancellationToken) { var unmergedDocumentChanges = new List <TextChange>(); var successfullyMergedChanges = ArrayBuilder <TextChange> .GetInstance(); var cumulativeChangeIndex = 0; var textchanges = await textDiffService.GetTextChangesAsync(oldDocument, newDocument, cancellationToken).ConfigureAwait(false); foreach (var change in textchanges) { while (cumulativeChangeIndex < cumulativeChanges.Count && cumulativeChanges[cumulativeChangeIndex].Span.End < change.Span.Start) { // Existing change that does not overlap with the current change in consideration successfullyMergedChanges.Add(cumulativeChanges[cumulativeChangeIndex]); cumulativeChangeIndex++; groupSessionInfo.IsolatedDiffs++; } if (cumulativeChangeIndex < cumulativeChanges.Count) { var cumulativeChange = cumulativeChanges[cumulativeChangeIndex]; if (!cumulativeChange.Span.IntersectsWith(change.Span)) { // The current change in consideration does not intersect with any existing change successfullyMergedChanges.Add(change); groupSessionInfo.IsolatedDiffs++; } else { if (change.Span != cumulativeChange.Span || change.NewText != cumulativeChange.NewText) { // The current change in consideration overlaps an existing change but // the changes are not identical. unmergedDocumentChanges.Add(change); groupSessionInfo.OverlappingDistinctDiffs++; if (change.Span == cumulativeChange.Span) { groupSessionInfo.OverlappingDistinctDiffsWithSameSpan++; if (change.NewText.Contains(cumulativeChange.NewText) || cumulativeChange.NewText.Contains(change.NewText)) { groupSessionInfo.OverlappingDistinctDiffsWithSameSpanAndSubstringRelation++; } } } else { // The current change in consideration is identical to an existing change successfullyMergedChanges.Add(change); cumulativeChangeIndex++; groupSessionInfo.IdenticalDiffs++; } } } else { // The current change in consideration does not intersect with any existing change successfullyMergedChanges.Add(change); groupSessionInfo.IsolatedDiffs++; } } while (cumulativeChangeIndex < cumulativeChanges.Count) { // Existing change that does not overlap with the current change in consideration successfullyMergedChanges.Add(cumulativeChanges[cumulativeChangeIndex]); cumulativeChangeIndex++; groupSessionInfo.IsolatedDiffs++; } if (unmergedDocumentChanges.Any()) { unmergedChanges.Add(new UnmergedDocumentChanges( unmergedDocumentChanges.AsEnumerable(), oldDocument.Project.Name, oldDocument.Id)); } return(successfullyMergedChanges.ToImmutableAndFree()); }