提交 0bf1b212 编写于 作者: A Andrew Casey

Re-integrate import lookup into submission walk

Look at the usings for each submission as we visit that submission.  The
mental model is a chain of ```InContainerBinder```s, but we don't actually
instantiate the chain for perf reasons.

TODO: Some tests are failing because of the new semantics.  The main issue
is that usings can now hide members (not just types).  No corresponding
issue exists in C# because usings can't appear within types.
上级 e031fa96
......@@ -758,7 +758,7 @@ private InContainerBinder MakeNamespaceBinder(CSharpSyntaxNode node, NameSyntax
NamespaceOrTypeSymbol container = outer.Container;
NamespaceSymbol ns = ((NamespaceSymbol)container).GetNestedNamespace(name);
if ((object)ns == null) return outer;
return new InContainerBinder(ns, outer, node, allowStaticClassUsings: ((CSharpParseOptions)syntaxTree.Options).LanguageVersion >= LanguageVersion.CSharp6, inUsing: inUsing);
return new InContainerBinder(ns, outer, node, inUsing: inUsing);
}
public override Binder VisitCompilationUnit(CompilationUnitSyntax parent)
......@@ -803,10 +803,7 @@ internal InContainerBinder VisitCompilationUnit(CompilationUnitSyntax compilatio
// + script class members & top-level using aliases
//
if (!inUsing)
{
result = new ExternalUsingsBinder(result);
}
result = new InContainerBinder(container: null, next: result, imports: compilation.GlobalImports);
result = new InContainerBinder(compilation.GlobalNamespace, result);
......@@ -827,7 +824,7 @@ internal InContainerBinder VisitCompilationUnit(CompilationUnitSyntax compilatio
importsContainer = compilation.GlobalNamespace;
}
result = new InContainerBinder(importsContainer, result, compilationUnit, allowStaticClassUsings: ((CSharpParseOptions)syntaxTree.Options).LanguageVersion >= LanguageVersion.CSharp6, inUsing: inUsing);
result = new InContainerBinder(importsContainer, result, compilationUnit, inUsing: inUsing);
binderCache.TryAdd(key, result);
}
......
......@@ -244,23 +244,23 @@ private void LookupMembersInSubmissions(LookupResult result, TypeSymbol submissi
{
submissionSymbols.Clear();
var submissionImports = submission.SubmissionImports;
if (submission != Compilation)
{
submissionImports = Imports.ExpandPreviousSubmissionImports(submissionImports, Compilation);
}
// If a viable using alias and a matching member are both defined in the submission an error is reported elsewhere.
// Ignore the member in such case.
if ((options & LookupOptions.NamespaceAliasesOnly) == 0 && (object)submission.ScriptClass != null)
{
LookupMembersWithoutInheritance(submissionSymbols, submission.ScriptClass, name, arity, options, originalBinder, submissionClass, diagnose, ref useSiteDiagnostics, basesBeingResolved);
}
// using aliases:
AliasAndUsingDirective directive;
var usingAliases = submission.SubmissionUsingAliases;
if (usingAliases != null && usingAliases.TryGetValue(name, out directive))
{
if (submissionSymbols.Symbols.Count > 0)
if (submissionSymbols.IsMultiViable && submissionImports.IsUsingAlias(name, originalBinder.IsSemanticModelBinder))
{
// using alias is ambiguous with another definition within the same submission iff the other definition is a 0-ary type or a non-type:
Symbol existingDefinition = submissionSymbols.Symbols.First();
if (existingDefinition.Kind == SymbolKind.NamedType && arity == 0 || existingDefinition.Kind != SymbolKind.NamedType)
if (existingDefinition.Kind != SymbolKind.NamedType || arity == 0)
{
CSDiagnosticInfo diagInfo = new CSDiagnosticInfo(ErrorCode.ERR_ConflictingAliasAndDefinition, name, existingDefinition.GetKindText());
var error = new ExtendedErrorTypeSymbol((NamespaceOrTypeSymbol)null, name, arity, diagInfo, unreported: true);
......@@ -268,9 +268,12 @@ private void LookupMembersInSubmissions(LookupResult result, TypeSymbol submissi
break;
}
}
}
// Note: all usings are considered used in submissions, so there's no reason to call MarkImportDirectiveAsUsed.
submissionSymbols.MergeEqual(originalBinder.CheckViability(directive.Alias, arity, options, null, diagnose, ref useSiteDiagnostics, basesBeingResolved));
if (!submissionSymbols.IsMultiViable)
{
// next try using aliases or symbols in imported namespaces
submissionImports.LookupSymbol(originalBinder, submissionSymbols, name, arity, basesBeingResolved, options, diagnose, ref useSiteDiagnostics);
}
if (lookingForOverloadsOfKind == null)
......@@ -1499,34 +1502,22 @@ private void AddMemberLookupSymbolsInfoInSubmissions(LookupSymbolsInfo result, T
for (CSharpCompilation submission = Compilation; submission != null; submission = submission.PreviousSubmission)
{
var usingAliases = submission.SubmissionUsingAliases?.Values;
if (usingAliases != null)
{
foreach (var usingAlias in usingAliases)
{
AddAliasSymbolToResult(result, usingAlias.Alias, options, originalBinder);
}
}
if ((object)submission.ScriptClass != null)
{
AddMemberLookupSymbolsInfoWithoutInheritance(result, submission.ScriptClass, options, originalBinder, scriptClass);
}
}
}
/// <remarks>
/// Note: we do not mark nodes when looking up arities or names. This is because these two
/// types of lookup are only around to make the public
/// SemanticModel.LookupNames/LookupSymbols work and do not count as usages of the directives
/// when the actual code is bound.
/// </remarks>
internal static void AddAliasSymbolToResult(LookupSymbolsInfo result, AliasSymbol aliasSymbol, LookupOptions options, Binder originalBinder)
{
var targetSymbol = aliasSymbol.GetAliasTarget(basesBeingResolved: null);
if (originalBinder.CanAddLookupSymbolInfo(targetSymbol, options, null))
{
result.AddSymbol(aliasSymbol, aliasSymbol.Name, 0);
// If we are looking only for labels we do not need to search through the imports.
// Submission imports are handled by AddMemberLookupSymbolsInfo (above).
if ((options & LookupOptions.LabelsOnly) == 0)
{
var submissionImports = submission.SubmissionImports;
if (submission != Compilation)
{
submissionImports = Imports.ExpandPreviousSubmissionImports(submissionImports, Compilation);
}
submissionImports.AddLookupSymbolsInfo(result, options, originalBinder);
}
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
internal class ExternalUsingsBinder : Binder
{
internal ExternalUsingsBinder(Binder next)
: base(next)
{
}
internal override void LookupSymbolsInSingleBinder(
LookupResult result, string name, int arity, ConsList<Symbol> basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
if (!ShouldLookInUsings(options))
{
return;
}
LookupResult tmp = LookupResult.GetInstance();
// usings:
Imports.LookupSymbolInUsings(Compilation.ExternalUsings, originalBinder, tmp, name, arity, basesBeingResolved, options, diagnose, ref useSiteDiagnostics);
// if we found a viable result in imported namespaces, use it instead of unviable symbols found in source:
if (tmp.IsMultiViable)
{
result.MergeEqual(tmp);
}
tmp.Free();
}
protected override void AddLookupSymbolsInfoInSingleBinder(
LookupSymbolsInfo result, LookupOptions options, Binder originalBinder)
{
if (!ShouldLookInUsings(options))
{
return;
}
// Add types within namespaces imported through usings, but don't add nested namespaces.
LookupOptions usingOptions = (options & ~(LookupOptions.NamespaceAliasesOnly | LookupOptions.NamespacesOrTypesOnly)) | LookupOptions.MustNotBeNamespace;
Imports.AddLookupSymbolsInfoInUsings(Compilation.ExternalUsings, originalBinder, result, usingOptions);
}
private static bool ShouldLookInUsings(LookupOptions options)
{
return (options & (LookupOptions.NamespaceAliasesOnly | LookupOptions.LabelsOnly)) == 0;
}
internal override bool SupportsExtensionMethods
{
get
{
return true;
}
}
internal override void GetCandidateExtensionMethods(
bool searchUsingsNotNamespace,
ArrayBuilder<MethodSymbol> methods,
string name,
int arity,
LookupOptions options,
bool isCallerSemanticModel)
{
if (!searchUsingsNotNamespace)
{
return;
}
foreach (var @using in Compilation.ExternalUsings)
{
if (@using.NamespaceOrType.Kind == SymbolKind.Namespace)
{
((NamespaceSymbol)@using.NamespaceOrType).GetExtensionMethods(methods, name, arity, options);
}
}
}
}
}
......@@ -251,16 +251,113 @@ public static Imports FromGlobalUsings(CSharpCompilation compilation)
}
}
uniqueUsings.Free();
if (diagnostics.IsEmptyWithoutResolution)
{
diagnostics = null;
}
var previousSubmissionImports = compilation.PreviousSubmission?.GlobalImports;
if (previousSubmissionImports != null)
{
// Currently, only usings are supported.
Debug.Assert(previousSubmissionImports.UsingAliases.IsEmpty);
Debug.Assert(previousSubmissionImports.ExternAliases.IsEmpty);
var expandedImports = ExpandPreviousSubmissionImports(previousSubmissionImports, compilation);
foreach (var previousUsing in expandedImports.Usings)
{
if (uniqueUsings.Add(previousUsing.NamespaceOrType))
{
boundUsings.Add(previousUsing);
}
}
}
uniqueUsings.Free();
return new Imports(compilation, ImmutableDictionary<string, AliasAndUsingDirective>.Empty, boundUsings.ToImmutableAndFree(), ImmutableArray<AliasAndExternAliasDirective>.Empty, diagnostics);
}
// TODO (https://github.com/dotnet/roslyn/issues/5517): skip namespace expansion if references haven't changed.
internal static Imports ExpandPreviousSubmissionImports(Imports previousSubmissionImports, CSharpCompilation newSubmission)
{
Debug.Assert(previousSubmissionImports != null);
Debug.Assert(previousSubmissionImports._compilation?.IsSubmission != false);
Debug.Assert(newSubmission.IsSubmission);
var expandedGlobalNamespace = newSubmission.GlobalNamespace;
var expandedAliases = ImmutableDictionary<string, AliasAndUsingDirective>.Empty;
if (!previousSubmissionImports.UsingAliases.IsEmpty)
{
var expandedAliasesBuilder = ImmutableDictionary.CreateBuilder<string, AliasAndUsingDirective>();
foreach (var pair in previousSubmissionImports.UsingAliases)
{
var name = pair.Key;
var directive = pair.Value;
expandedAliasesBuilder.Add(name, new AliasAndUsingDirective(directive.Alias.ToNewSubmission(newSubmission), directive.UsingDirective));
}
expandedAliases = expandedAliasesBuilder.ToImmutable();
}
var expandedUsings = ImmutableArray<NamespaceOrTypeAndUsingDirective>.Empty;
if (!previousSubmissionImports.Usings.IsEmpty)
{
var expandedUsingsBuilder = ArrayBuilder<NamespaceOrTypeAndUsingDirective>.GetInstance(previousSubmissionImports.Usings.Length);
foreach (var previousUsing in previousSubmissionImports.Usings)
{
var previousTarget = previousUsing.NamespaceOrType;
if (previousTarget.IsType)
{
expandedUsingsBuilder.Add(previousUsing);
}
else
{
var expandedNamespace = ExpandPreviousSubmissionNamespace((NamespaceSymbol)previousTarget, expandedGlobalNamespace);
expandedUsingsBuilder.Add(new NamespaceOrTypeAndUsingDirective(expandedNamespace, previousUsing.UsingDirective));
}
}
expandedUsings = expandedUsingsBuilder.ToImmutableAndFree();
}
return new Imports(
newSubmission,
expandedAliases,
expandedUsings,
previousSubmissionImports.ExternAliases,
diagnostics: null);
}
internal static NamespaceSymbol ExpandPreviousSubmissionNamespace(NamespaceSymbol originalNamespace, NamespaceSymbol expandedGlobalNamespace)
{
// Soft assert: we'll still do the right thing if it fails.
Debug.Assert(!originalNamespace.IsGlobalNamespace, "Global using to global namespace");
// Hard assert: we depend on this.
Debug.Assert(expandedGlobalNamespace.IsGlobalNamespace, "Global namespace required");
var nameParts = ArrayBuilder<string>.GetInstance();
var curr = originalNamespace;
while (!curr.IsGlobalNamespace)
{
nameParts.Add(curr.Name);
curr = curr.ContainingNamespace;
}
var expandedNamespace = expandedGlobalNamespace;
for (int i = nameParts.Count - 1; i >= 0; i--)
{
// Note, the name may have become ambiguous (e.g. if a type with the same name
// is now in scope), but we're not rebinding - we're just expanding to the
// current contents of the same namespace.
expandedNamespace = expandedNamespace.GetMembers(nameParts[i]).OfType<NamespaceSymbol>().Single();
}
nameParts.Free();
return expandedNamespace;
}
public static Imports FromCustomDebugInfo(
CSharpCompilation compilation,
ImmutableDictionary<string, AliasAndUsingDirective> usingAliases,
......@@ -595,21 +692,34 @@ internal bool IsUsingAlias(string name, bool callerIsSemanticModel)
// SemanticModel.LookupNames/LookupSymbols work and do not count as usages of the directives
// when the actual code is bound.
internal void AddLookupSymbolsInfoInAliases(Binder originalBinder, LookupSymbolsInfo result, LookupOptions options)
internal void AddLookupSymbolsInfo(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder)
{
foreach (var usingAlias in this.UsingAliases.Values)
{
Binder.AddAliasSymbolToResult(result, usingAlias.Alias, options, originalBinder);
AddAliasSymbolToResult(result, usingAlias.Alias, options, originalBinder);
}
foreach (var externAlias in this.ExternAliases)
{
Binder.AddAliasSymbolToResult(result, externAlias.Alias, options, originalBinder);
AddAliasSymbolToResult(result, externAlias.Alias, options, originalBinder);
}
// Add types within namespaces imported through usings, but don't add nested namespaces.
LookupOptions usingOptions = (options & ~(LookupOptions.NamespaceAliasesOnly | LookupOptions.NamespacesOrTypesOnly)) | LookupOptions.MustNotBeNamespace;
AddLookupSymbolsInfoInUsings(this.Usings, result, usingOptions, originalBinder);
}
private static void AddAliasSymbolToResult(LookupSymbolsInfo result, AliasSymbol aliasSymbol, LookupOptions options, Binder originalBinder)
{
var targetSymbol = aliasSymbol.GetAliasTarget(basesBeingResolved: null);
if (originalBinder.CanAddLookupSymbolInfo(targetSymbol, options, null))
{
result.AddSymbol(aliasSymbol, aliasSymbol.Name, 0);
}
}
internal static void AddLookupSymbolsInfoInUsings(
ImmutableArray<NamespaceOrTypeAndUsingDirective> usings, Binder originalBinder, LookupSymbolsInfo result, LookupOptions options)
private static void AddLookupSymbolsInfoInUsings(
ImmutableArray<NamespaceOrTypeAndUsingDirective> usings, LookupSymbolsInfo result, LookupOptions options, Binder originalBinder)
{
Debug.Assert(!options.CanConsiderNamespaces());
......
......@@ -16,8 +16,7 @@ internal sealed class InContainerBinder : Binder
{
private readonly NamespaceOrTypeSymbol _container;
private readonly CSharpSyntaxNode _declarationSyntax;
private readonly bool _allowStaticClassUsings;
private Imports _imports; // might be initialized lazily
private Imports _lazyImports;
private ImportChain _lazyImportChain;
private readonly bool _inUsing;
......@@ -25,7 +24,7 @@ internal sealed class InContainerBinder : Binder
/// Creates a binder for a container with imports (usings and extern aliases) that can be
/// retrieved from <paramref name="declarationSyntax"/>.
/// </summary>
internal InContainerBinder(NamespaceOrTypeSymbol container, Binder next, CSharpSyntaxNode declarationSyntax, bool allowStaticClassUsings, bool inUsing)
internal InContainerBinder(NamespaceOrTypeSymbol container, Binder next, CSharpSyntaxNode declarationSyntax, bool inUsing)
: base(next)
{
Debug.Assert((object)container != null);
......@@ -33,7 +32,6 @@ internal InContainerBinder(NamespaceOrTypeSymbol container, Binder next, CSharpS
_declarationSyntax = declarationSyntax;
_container = container;
_allowStaticClassUsings = allowStaticClassUsings;
_inUsing = inUsing;
}
......@@ -43,10 +41,10 @@ internal InContainerBinder(NamespaceOrTypeSymbol container, Binder next, CSharpS
internal InContainerBinder(NamespaceOrTypeSymbol container, Binder next, Imports imports = null)
: base(next)
{
Debug.Assert((object)container != null);
Debug.Assert((object)container != null || imports != null);
_container = container;
_imports = imports ?? Imports.Empty;
_lazyImports = imports ?? Imports.Empty;
}
internal NamespaceOrTypeSymbol Container
......@@ -57,14 +55,6 @@ internal NamespaceOrTypeSymbol Container
}
}
internal bool AllowStaticClassUsings
{
get
{
return _allowStaticClassUsings;
}
}
internal Imports GetImports()
{
return GetImports(basesBeingResolved: null);
......@@ -72,12 +62,12 @@ internal Imports GetImports()
private Imports GetImports(ConsList<Symbol> basesBeingResolved)
{
if (_imports == null)
if (_lazyImports == null)
{
Interlocked.CompareExchange(ref _imports, Imports.FromSyntax(_declarationSyntax, this, basesBeingResolved, _inUsing), null);
Interlocked.CompareExchange(ref _lazyImports, Imports.FromSyntax(_declarationSyntax, this, basesBeingResolved, _inUsing), null);
}
return _imports;
return _lazyImports;
}
internal override ImportChain ImportChain
......@@ -87,7 +77,7 @@ internal override ImportChain ImportChain
if (_lazyImportChain == null)
{
ImportChain importChain = this.Next.ImportChain;
if (_container.Kind == SymbolKind.Namespace)
if ((object)_container == null || _container.Kind == SymbolKind.Namespace)
{
importChain = new ImportChain(GetImports(), importChain);
}
......@@ -112,7 +102,7 @@ internal override Symbol ContainingMemberOrLambda
internal bool IsSubmissionClass
{
get { return (_container.Kind == SymbolKind.NamedType) && ((NamedTypeSymbol)_container).IsSubmissionClass; }
get { return (_container?.Kind == SymbolKind.NamedType) && ((NamedTypeSymbol)_container).IsSubmissionClass; }
}
internal override bool IsAccessibleHelper(Symbol symbol, TypeSymbol accessThroughType, out bool failedThroughTypeCheck, ref HashSet<DiagnosticInfo> useSiteDiagnostics, ConsList<Symbol> basesBeingResolved)
......@@ -145,22 +135,15 @@ internal override bool SupportsExtensionMethods
{
this.GetImports().LookupExtensionMethodsInUsings(methods, name, arity, options, isCallerSemanticModel);
}
else
else if (_container?.Kind == SymbolKind.Namespace)
{
if (_container.Kind == SymbolKind.Namespace)
{
((NamespaceSymbol)_container).GetExtensionMethods(methods, name, arity, options);
}
else if (((NamedTypeSymbol)_container).IsScriptClass)
((NamespaceSymbol)_container).GetExtensionMethods(methods, name, arity, options);
}
else if (IsSubmissionClass)
{
for (var submission = this.Compilation; submission != null; submission = submission.PreviousSubmission)
{
for (var submission = this.Compilation; submission != null; submission = submission.PreviousSubmission)
{
var scriptClass = submission.ScriptClass;
if ((object)scriptClass != null)
{
scriptClass.GetExtensionMethods(methods, name, arity, options);
}
}
submission.ScriptClass?.GetExtensionMethods(methods, name, arity, options);
}
}
}
......@@ -175,14 +158,11 @@ internal override bool SupportsExtensionMethods
if (IsSubmissionClass)
{
this.LookupMembersInternal(result, _container, name, arity, basesBeingResolved, options, originalBinder, diagnose, ref useSiteDiagnostics);
// next try using aliases or symbols in imported namespaces
Imports.LookupSymbolInUsings(imports.Usings, originalBinder, result, name, arity, basesBeingResolved, options, diagnose, ref useSiteDiagnostics);
return;
}
// first lookup members of the namespace
if ((options & LookupOptions.NamespaceAliasesOnly) == 0)
if ((options & LookupOptions.NamespaceAliasesOnly) == 0 && _container != null)
{
this.LookupMembersInternal(result, _container, name, arity, basesBeingResolved, options, originalBinder, diagnose, ref useSiteDiagnostics);
......@@ -206,18 +186,17 @@ internal override bool SupportsExtensionMethods
protected override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder)
{
this.AddMemberLookupSymbolsInfo(result, _container, options, originalBinder);
if (_container != null)
{
this.AddMemberLookupSymbolsInfo(result, _container, options, originalBinder);
}
// if we are looking only for labels we do not need to search through the imports
// If we are looking only for labels we do not need to search through the imports.
// Submission imports are handled by AddMemberLookupSymbolsInfo (above).
if (!IsSubmissionClass && ((options & LookupOptions.LabelsOnly) == 0))
{
var imports = GetImports(basesBeingResolved: null);
imports.AddLookupSymbolsInfoInAliases(originalBinder, result, options);
// Add types within namespaces imported through usings, but don't add nested namespaces.
LookupOptions usingOptions = (options & ~(LookupOptions.NamespaceAliasesOnly | LookupOptions.NamespacesOrTypesOnly)) | LookupOptions.MustNotBeNamespace;
Imports.AddLookupSymbolsInfoInUsings(imports.Usings, originalBinder, result, usingOptions);
imports.AddLookupSymbolsInfo(result, options, originalBinder);
}
}
......
......@@ -187,7 +187,6 @@
<Compile Include="Binder\SwitchBinder.cs" />
<Compile Include="Binder\SimpleLocalScopeBinder.cs" />
<Compile Include="Binder\TypeofBinder.cs" />
<Compile Include="Binder\ExternalUsingsBinder.cs" />
<Compile Include="Binder\UsingStatementBinder.cs" />
<Compile Include="Binder\WhileBinder.cs" />
<Compile Include="Binder\WithClassTypeParametersBinder.cs" />
......
......@@ -45,7 +45,7 @@ public sealed partial class CSharpCompilation : Compilation
internal static readonly ParallelOptions DefaultParallelOptions = new ParallelOptions();
private readonly CSharpCompilationOptions _options;
private readonly Lazy<ImmutableArray<NamespaceOrTypeAndUsingDirective>> _externalUsings;
private readonly Lazy<Imports> _globalImports;
private readonly Lazy<AliasSymbol> _globalNamespaceAlias; // alias symbol used to resolve "global::".
private readonly Lazy<ImplicitNamedTypeSymbol> _scriptClass;
private readonly CSharpCompilation _previousSubmission;
......@@ -292,7 +292,7 @@ public override INamedTypeSymbol CreateErrorTypeSymbol(INamespaceOrTypeSymbol co
this.builtInOperators = new BuiltInOperators(this);
_scriptClass = new Lazy<ImplicitNamedTypeSymbol>(BindScriptClass);
_externalUsings = new Lazy<ImmutableArray<NamespaceOrTypeAndUsingDirective>>(BindExternalUsings);
_globalImports = new Lazy<Imports>(BindGlobalImports);
_globalNamespaceAlias = new Lazy<AliasSymbol>(CreateGlobalNamespaceAlias);
_anonymousTypeManager = new AnonymousTypeManager(this);
this.LanguageVersion = CommonLanguageVersion(syntaxAndDeclarations.ExternalSyntaxTrees);
......@@ -1196,117 +1196,16 @@ private ImplicitNamedTypeSymbol BindScriptClass()
}
/// <summary>
/// Usings that are not from source. For regular compilations, these are the global usings.
/// For submissions, global and declared usings from previous submissions are also included.
/// Global imports (including those from previous submissions, if there are any).
/// </summary>
/// <remarks>
/// Always consider whether usings should be considered before accessing this (e.g. not when binding other usings).
/// </remarks>
internal ImmutableArray<NamespaceOrTypeAndUsingDirective> ExternalUsings => _externalUsings.Value;
private ImmutableArray<NamespaceOrTypeAndUsingDirective> BindExternalUsings()
{
var globalImports = Imports.FromGlobalUsings(this);
globalImports.Complete(CancellationToken.None);
var newUsings = globalImports.Usings;
var previousSubmission = this.PreviousSubmission;
if (previousSubmission == null)
{
return newUsings;
}
var externalUsings = ArrayBuilder<NamespaceOrTypeAndUsingDirective>.GetInstance();
var uniqueTargets = PooledHashSet<NamespaceOrTypeSymbol>.GetInstance();
internal Imports GlobalImports => _globalImports.Value;
// The previous submission should not have had extern aliases (unsupported)
// and using aliases are handled separately (during lookup) so we only need
// to extract the regular usings.
Debug.Assert(previousSubmission.SubmissionImports.ExternAliases.Length == 0);
// TODO (https://github.com/dotnet/roslyn/issues/5517): uncomment
//if (this.ReferenceManagerEquals(previousSubmission))
//{
// foreach (var previousUsing in previousSubmission.SubmissionImports.Usings)
// {
// if (uniqueTargets.Add(previousUsing.NamespaceOrType))
// {
// externalUsings.Add(previousUsing);
// }
// }
//}
//else
{
foreach (var previousUsing in previousSubmission.ExternalUsings.Concat(previousSubmission.SubmissionImports.Usings))
{
var previousTarget = previousUsing.NamespaceOrType;
if (previousTarget.IsType)
{
if (uniqueTargets.Add(previousTarget))
{
externalUsings.Add(previousUsing);
}
}
else
{
var expandedNamespace = ExpandPreviousSubmissionNamespace((NamespaceSymbol)previousTarget, this.GlobalNamespace);
if (uniqueTargets.Add(expandedNamespace))
{
externalUsings.Add(new NamespaceOrTypeAndUsingDirective(expandedNamespace, previousUsing.UsingDirective));
}
}
}
}
foreach (var newUsing in newUsings)
{
if (uniqueTargets.Add(newUsing.NamespaceOrType))
{
externalUsings.Add(newUsing);
}
}
uniqueTargets.Free();
return externalUsings.ToImmutableAndFree();
}
private static NamespaceSymbol ExpandPreviousSubmissionNamespace(NamespaceSymbol originalNamespace, NamespaceSymbol expandedGlobalNamespace)
{
// Soft assert: we'll still do the right thing if it fails.
Debug.Assert(!originalNamespace.IsGlobalNamespace, "Global using to global namespace");
var nameParts = ArrayBuilder<string>.GetInstance();
var curr = originalNamespace;
while (!curr.IsGlobalNamespace)
{
nameParts.Add(curr.Name);
curr = curr.ContainingNamespace;
}
var expandedNamespace = expandedGlobalNamespace;
for (int i = nameParts.Count - 1; i >= 0; i--)
{
// Note, the name may have become ambiguous (e.g. if a type with the same name
// is now in scope), but we're not rebinding - we're just expanding to the
// current contents of the same namespace.
expandedNamespace = expandedNamespace.GetMembers(nameParts[i]).OfType<NamespaceSymbol>().Single();
}
nameParts.Free();
return expandedNamespace;
}
private Imports BindGlobalImports() => Imports.FromGlobalUsings(this);
/// <summary>
/// Using aliases declared by this submission (null if this isn't one).
/// Imports declared by this submission (null if this isn't one).
/// </summary>
/// <remarks>
/// Always consider whether usings should be considered before accessing this (e.g. not when binding other usings).
/// </remarks>
internal ImmutableDictionary<string, AliasAndUsingDirective> SubmissionUsingAliases => SubmissionImports?.UsingAliases;
private Imports SubmissionImports
internal Imports SubmissionImports
{
get
{
......@@ -1319,7 +1218,7 @@ private Imports SubmissionImports
var tree = _syntaxAndDeclarations.ExternalSyntaxTrees.SingleOrDefault();
if (tree == null)
{
return null;
return Imports.Empty;
}
var binder = GetBinderFactory(tree).GetImportsBinder((CSharpSyntaxNode)tree.GetRoot());
......@@ -2191,7 +2090,7 @@ private bool FilterAndAppendDiagnostics(DiagnosticBag accumulator, IEnumerable<D
private ImmutableArray<Diagnostic> GetSourceDeclarationDiagnostics(SyntaxTree syntaxTree = null, TextSpan? filterSpanWithinTree = null, Func<IEnumerable<Diagnostic>, SyntaxTree, TextSpan?, IEnumerable<Diagnostic>> locationFilterOpt = null, CancellationToken cancellationToken = default(CancellationToken))
{
var dummy = ExternalUsings; // Force completion.
GlobalImports.Complete(cancellationToken);
SourceLocation location = null;
if (syntaxTree != null)
......
......@@ -97,6 +97,23 @@ internal static AliasSymbol CreateCustomDebugInfoAlias(NamespaceOrTypeSymbol tar
return new AliasSymbol(binder, targetSymbol, aliasToken, ImmutableArray.Create(aliasToken.GetLocation()));
}
internal AliasSymbol ToNewSubmission(CSharpCompilation compilation)
{
Debug.Assert(_state.HasComplete(CompletionPart.AliasTarget));
Debug.Assert(_binder.Compilation.IsSubmission);
var previousTarget = _aliasTarget;
if (previousTarget.Kind != SymbolKind.Namespace)
{
return this;
}
var expandedGlobalNamespace = compilation.GlobalNamespace;
var expandedNamespace = Imports.ExpandPreviousSubmissionNamespace((NamespaceSymbol)previousTarget, expandedGlobalNamespace);
var binder = new InContainerBinder(expandedGlobalNamespace, new BuckStopsHereBinder(compilation));
return new AliasSymbol(binder, expandedNamespace, _aliasName, _locations);
}
public override string Name
{
get
......
......@@ -531,7 +531,7 @@ public static class CInner
// using static NInner.CInner;
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "NInner").WithArguments("NInner").WithLocation(1, 14));
}
private static Symbol GetSpeculativeSymbol(CSharpCompilation comp, string name)
{
var tree = comp.SyntaxTrees.Single();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册