| File: Compilation\CSharpCompilation.UsingsFromOptionsAndDiagnostics.cs | Web Access |
| Project: src\roslyn\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Collections.Immutable; using System.Diagnostics; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp { partial class CSharpCompilation { private class UsingsFromOptionsAndDiagnostics { public static readonly UsingsFromOptionsAndDiagnostics Empty = new UsingsFromOptionsAndDiagnostics() { UsingNamespacesOrTypes = ImmutableArray<NamespaceOrTypeAndUsingDirective>.Empty, Diagnostics = null }; public ImmutableArray<NamespaceOrTypeAndUsingDirective> UsingNamespacesOrTypes { get; init; } public DiagnosticBag? Diagnostics { get; init; } // completion state that tracks whether validation was done/not done/currently in process. private SymbolCompletionState _state; public static UsingsFromOptionsAndDiagnostics FromOptions(CSharpCompilation compilation) { var usings = compilation.Options.Usings; if (usings.Length == 0) { return Empty; } var diagnostics = new DiagnosticBag(); var usingsBinder = new InContainerBinder(compilation.GlobalNamespace, new BuckStopsHereBinder(compilation, associatedFileIdentifier: null)); var boundUsings = ArrayBuilder<NamespaceOrTypeAndUsingDirective>.GetInstance(); var uniqueUsings = PooledHashSet<NamespaceOrTypeSymbol>.GetInstance(); foreach (string @using in usings) { if (!@using.IsValidClrNamespaceName()) { continue; } string[] identifiers = @using.Split('.'); NameSyntax qualifiedName = SyntaxFactory.IdentifierName(identifiers[0]); for (int j = 1; j < identifiers.Length; j++) { qualifiedName = SyntaxFactory.QualifiedName(left: qualifiedName, right: SyntaxFactory.IdentifierName(identifiers[j])); } var directiveDiagnostics = BindingDiagnosticBag.GetInstance(); Debug.Assert(directiveDiagnostics.DiagnosticBag is object); Debug.Assert(directiveDiagnostics.DependenciesBag is object); var imported = usingsBinder.BindNamespaceOrTypeSymbol(qualifiedName, directiveDiagnostics).NamespaceOrTypeSymbol; if (uniqueUsings.Add(imported)) { boundUsings.Add(new NamespaceOrTypeAndUsingDirective(imported, null, dependencies: directiveDiagnostics.DependenciesBag.ToImmutableArray())); } diagnostics.AddRange(directiveDiagnostics.DiagnosticBag); directiveDiagnostics.Free(); } if (diagnostics.IsEmptyWithoutResolution) { diagnostics = null; } uniqueUsings.Free(); if (boundUsings.Count == 0 && diagnostics is null) { boundUsings.Free(); return Empty; } return new UsingsFromOptionsAndDiagnostics() { UsingNamespacesOrTypes = boundUsings.ToImmutableAndFree(), Diagnostics = diagnostics }; } internal void Complete(CSharpCompilation compilation, CancellationToken cancellationToken) { while (true) { cancellationToken.ThrowIfCancellationRequested(); var incompletePart = _state.NextIncompletePart; switch (incompletePart) { case CompletionPart.StartValidatingImports: { if (_state.NotePartComplete(CompletionPart.StartValidatingImports)) { Validate(compilation); _state.NotePartComplete(CompletionPart.FinishValidatingImports); } } break; case CompletionPart.FinishValidatingImports: // some other thread has started validating imports (otherwise we would be in the case above) so // we just wait for it to both finish and report the diagnostics. Debug.Assert(_state.HasComplete(CompletionPart.StartValidatingImports)); _state.SpinWaitComplete(CompletionPart.FinishValidatingImports, cancellationToken); break; case CompletionPart.None: return; default: // any other values are completion parts intended for other kinds of symbols _state.NotePartComplete(CompletionPart.All & ~CompletionPart.ImportsAll); break; } _state.SpinWaitComplete(incompletePart, cancellationToken); } } private void Validate(CSharpCompilation compilation) { if (this == Empty) { return; } DiagnosticBag semanticDiagnostics = compilation.DeclarationDiagnostics; var diagnostics = BindingDiagnosticBag.GetInstance(); Debug.Assert(diagnostics.DiagnosticBag is object); Debug.Assert(diagnostics.DependenciesBag is object); var corLibrary = compilation.SourceAssembly.CorLibrary; var conversions = corLibrary.TypeConversions; foreach (var @using in UsingNamespacesOrTypes) { diagnostics.Clear(); diagnostics.AddDependencies(@using.Dependencies); NamespaceOrTypeSymbol target = @using.NamespaceOrType; // Check if `using static` directives meet constraints. Debug.Assert(@using.UsingDirective is null); if (target.IsType) { var typeSymbol = (TypeSymbol)target; var location = NoLocation.Singleton; typeSymbol.CheckAllConstraints(compilation, conversions, location, diagnostics); } semanticDiagnostics.AddRange(diagnostics.DiagnosticBag); recordImportDependencies(target); } if (Diagnostics != null && !Diagnostics.IsEmptyWithoutResolution) { semanticDiagnostics.AddRange(Diagnostics.AsEnumerable()); } diagnostics.Free(); void recordImportDependencies(NamespaceOrTypeSymbol target) { if (target.IsNamespace) { diagnostics.AddAssembliesUsedByNamespaceReference((NamespaceSymbol)target); } compilation.AddUsedAssemblies(diagnostics.DependenciesBag); } } } } }