提交 1177e33c 编写于 作者: A Andrew Casey

Revise script binder chain

 1. Look for declarations in the current submission (including aliases).
 2. Look for declarations in preceding submissions (including aliases), in
 order.
 3. Look for members in the host object (if any).
 4. Look for declarations in the global namespace.
 5. Look in usings (except aliases) in the current submission and all
 preceding submissions (all at once, not looping).
 6. Look in the global imports of the current submission and all preceding
 submissions (all at once, not looping).

Note that 5, 6, and aliases from 1 are skipped if we are binding the
target of a using in the current submission.

Fixes #5450
Fixes #4811
上级 6ac25776
......@@ -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)
......@@ -786,8 +786,6 @@ internal InContainerBinder VisitCompilationUnit(CompilationUnitSyntax compilatio
{
result = this.buckStopsHereBinder;
NamespaceOrTypeSymbol importsContainer;
if (inScript)
{
Debug.Assert((object)compilation.ScriptClass != null);
......@@ -795,22 +793,31 @@ internal InContainerBinder VisitCompilationUnit(CompilationUnitSyntax compilatio
//
// Binder chain in script/interactive code:
//
// + global usings
// + interactive usings (in an interactive session)
// + global imports
// + current and previous submission imports (except using aliases)
// + global namespace
// + host object members
// + previous submissions (in an interactive submission)
// + script class members & top-level using aliases
// + previous submissions and corresponding using aliases
// + script class members and using aliases
//
if (compilation.GlobalImports.Usings.Length > 0)
// This is declared here so it can be captured. It's initialized below.
InContainerBinder scriptClassBinder = null;
if (inUsing)
{
result = new UsingsBinder(result, compilation.GlobalImports.Usings);
result = result.WithAdditionalFlags(BinderFlags.InScriptUsing);
}
if (compilation.IsSubmission)
else
{
result = new InteractiveUsingsBinder(result);
result = new InContainerBinder(container: null, next: result, imports: compilation.GlobalImports);
// NB: This binder has a full Imports object, but only the non-alias imports are
// ever consumed. Aliases are actually checked in scriptClassBinder (below).
result = compilation.PreviousSubmission == null
? new InContainerBinder(result, basesBeingResolved => scriptClassBinder.GetImports(basesBeingResolved))
: new InContainerBinder(result, basesBeingResolved =>
compilation.PreviousSubmissionImports.Concat(scriptClassBinder.GetImports(basesBeingResolved)));
}
result = new InContainerBinder(compilation.GlobalNamespace, result);
......@@ -820,7 +827,8 @@ internal InContainerBinder VisitCompilationUnit(CompilationUnitSyntax compilatio
result = new HostObjectModelBinder(result);
}
importsContainer = compilation.ScriptClass;
scriptClassBinder = new InContainerBinder(compilation.ScriptClass, result, compilationUnit, inUsing: inUsing);
result = scriptClassBinder;
}
else
{
......@@ -829,10 +837,9 @@ internal InContainerBinder VisitCompilationUnit(CompilationUnitSyntax compilatio
//
// + global namespace with top-level imports
//
importsContainer = compilation.GlobalNamespace;
result = new InContainerBinder(compilation.GlobalNamespace, result, compilationUnit, inUsing: inUsing);
}
result = new InContainerBinder(importsContainer, result, compilationUnit, allowStaticClassUsings: ((CSharpParseOptions)syntaxTree.Options).LanguageVersion >= LanguageVersion.CSharp6, inUsing: inUsing);
binderCache.TryAdd(key, result);
}
......
......@@ -127,7 +127,8 @@ internal Binder GetBinder(CSharpSyntaxNode node, int position)
/// Specify <see cref="NamespaceDeclarationSyntax"/> imports in the corresponding namespace, or
/// <see cref="CompilationUnitSyntax"/> for top-level imports.
/// </param>
internal InContainerBinder GetImportsBinder(CSharpSyntaxNode unit)
/// <param name="inUsing">True if the binder will be used to bind a using directive.</param>
internal InContainerBinder GetImportsBinder(CSharpSyntaxNode unit, bool inUsing = false)
{
switch (unit.Kind())
{
......@@ -135,7 +136,7 @@ internal InContainerBinder GetImportsBinder(CSharpSyntaxNode unit)
{
BinderFactoryVisitor visitor = _binderFactoryVisitorPool.Allocate();
visitor.Position = 0;
var result = visitor.VisitNamespaceDeclaration((NamespaceDeclarationSyntax)unit, unit.SpanStart, inBody: true, inUsing: false);
var result = visitor.VisitNamespaceDeclaration((NamespaceDeclarationSyntax)unit, unit.SpanStart, inBody: true, inUsing: inUsing);
_binderFactoryVisitorPool.Free(visitor);
return result;
}
......@@ -145,7 +146,7 @@ internal InContainerBinder GetImportsBinder(CSharpSyntaxNode unit)
{
BinderFactoryVisitor visitor = _binderFactoryVisitorPool.Allocate();
visitor.Position = 0;
var result = visitor.VisitCompilationUnit((CompilationUnitSyntax)unit, inUsing: false, inScript: InScript);
var result = visitor.VisitCompilationUnit((CompilationUnitSyntax)unit, inUsing: inUsing, inScript: InScript);
_binderFactoryVisitorPool.Free(visitor);
return result;
}
......@@ -154,26 +155,5 @@ internal InContainerBinder GetImportsBinder(CSharpSyntaxNode unit)
return null;
}
}
internal InteractiveUsingsBinder GetInteractiveUsingsBinder()
{
Debug.Assert(_compilation.IsSubmission);
BinderFactoryVisitor visitor = _binderFactoryVisitorPool.Allocate();
visitor.Position = 0;
Binder binder = visitor.VisitCompilationUnit(_syntaxTree.GetCompilationUnitRoot(), inUsing: false, inScript: true);
_binderFactoryVisitorPool.Free(visitor);
if (_compilation.HostObjectType != null)
{
binder = binder.Next;
Debug.Assert(binder is HostObjectModelBinder);
}
Debug.Assert(binder.Next is InContainerBinder);
return (InteractiveUsingsBinder)binder.Next.Next;
}
}
}
......@@ -87,6 +87,12 @@ internal enum BinderFlags : uint
/// </summary>
IgnoreCorLibraryDuplicatedTypes = 1 << 26,
/// <summary>
/// When binding imports in scripts/submissions, using aliases (other than from the current submission)
/// are considered but other imports are not.
/// </summary>
InScriptUsing = 1 << 27,
// Groups
AllClearedAtExecutableCodeBoundary = InLockBody | InCatchBlock | InCatchFilter | InFinallyBlock | InTryBlockOfTryCatch | InNestedFinallyBlock,
......
......@@ -244,29 +244,44 @@ private void LookupMembersInSubmissions(LookupResult result, TypeSymbol submissi
{
submissionSymbols.Clear();
var isCurrentSubmission = submission == Compilation;
var considerUsings = !(isCurrentSubmission && this.Flags.Includes(BinderFlags.InScriptUsing));
var submissionImports = considerUsings ? submission.SubmissionImports : Imports.Empty;
// 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);
// NB: It doesn't matter that submissionImports hasn't been expanded since we're not actually using the alias target.
if (submissionSymbols.IsMultiViable &&
considerUsings &&
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)
{
CSDiagnosticInfo diagInfo = new CSDiagnosticInfo(ErrorCode.ERR_ConflictingAliasAndDefinition, name, existingDefinition.GetKindText());
var error = new ExtendedErrorTypeSymbol((NamespaceOrTypeSymbol)null, name, arity, diagInfo, unreported: true);
result.SetFrom(LookupResult.Good(error)); // force lookup to be done w/ error symbol as result
break;
}
}
}
// using aliases:
Imports imports = submission.GetSubmissionImports();
if (submissionSymbols.Symbols.Count > 0 && imports.IsUsingAlias(name, this.IsSemanticModelBinder))
if (!submissionSymbols.IsMultiViable && considerUsings)
{
// 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 (!isCurrentSubmission)
{
CSDiagnosticInfo diagInfo = new CSDiagnosticInfo(ErrorCode.ERR_ConflictingAliasAndDefinition, name, existingDefinition.GetKindText());
var error = new ExtendedErrorTypeSymbol((NamespaceOrTypeSymbol)null, name, arity, diagInfo, unreported: true);
result.SetFrom(LookupResult.Good(error)); // force lookup to be done w/ error symbol as result
break;
submissionImports = Imports.ExpandPreviousSubmissionImports(submissionImports, Compilation);
}
}
imports.LookupSymbolInAliases(originalBinder, submissionSymbols, name, arity, basesBeingResolved, options, diagnose, ref useSiteDiagnostics);
// NB: We diverge from InContainerBinder here and only look in aliases.
// In submissions, regular usings are bubbled up to the outermost scope.
submissionImports.LookupSymbolInAliases(originalBinder, submissionSymbols, name, arity, basesBeingResolved, options, diagnose, ref useSiteDiagnostics);
}
if (lookingForOverloadsOfKind == null)
{
......@@ -337,7 +352,7 @@ private void LookupExtensionMethodsInSingleBinder(ExtensionMethodScope scope, Lo
{
var methods = ArrayBuilder<MethodSymbol>.GetInstance();
var binder = scope.Binder;
binder.GetCandidateExtensionMethods(scope.SearchUsingsNotNamespace, methods, name, arity, options, this.IsSemanticModelBinder);
binder.GetCandidateExtensionMethods(scope.SearchUsingsNotNamespace, methods, name, arity, options, this);
foreach (var method in methods)
{
......@@ -611,7 +626,7 @@ internal virtual bool SupportsExtensionMethods
string name,
int arity,
LookupOptions options,
bool isCallerSemanticModel)
Binder originalBinder)
{
}
......@@ -1493,11 +1508,26 @@ private void AddMemberLookupSymbolsInfoInSubmissions(LookupSymbolsInfo result, T
// TODO: optimize lookup (there might be many interactions in the chain)
for (CSharpCompilation submission = Compilation; submission != null; submission = submission.PreviousSubmission)
{
submission.GetSubmissionImports().AddLookupSymbolsInfoInAliases(this, result, options);
if ((object)submission.ScriptClass != null)
{
AddMemberLookupSymbolsInfoWithoutInheritance(result, submission.ScriptClass, options, originalBinder, scriptClass);
}
bool isCurrentSubmission = submission == Compilation;
// If we are looking only for labels we do not need to search through the imports.
if ((options & LookupOptions.LabelsOnly) == 0 && !(isCurrentSubmission && this.Flags.Includes(BinderFlags.InScriptUsing)))
{
var submissionImports = submission.SubmissionImports;
if (!isCurrentSubmission)
{
submissionImports = Imports.ExpandPreviousSubmissionImports(submissionImports, Compilation);
}
// NB: We diverge from InContainerBinder here and only look in aliases.
// In submissions, regular usings are bubbled up to the outermost scope.
submissionImports.AddLookupSymbolsInfoInAliases(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;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
......@@ -62,10 +63,10 @@ internal sealed class Imports
SyntaxList<ExternAliasDirectiveSyntax> externAliasDirectives;
if (declarationSyntax.Kind() == SyntaxKind.CompilationUnit)
{
var compilation = (CompilationUnitSyntax)declarationSyntax;
var compilationUnit = (CompilationUnitSyntax)declarationSyntax;
// using directives are not in scope within using directives
usingDirectives = inUsing ? default(SyntaxList<UsingDirectiveSyntax>) : compilation.Usings;
externAliasDirectives = compilation.Externs;
usingDirectives = inUsing ? default(SyntaxList<UsingDirectiveSyntax>) : compilationUnit.Usings;
externAliasDirectives = compilationUnit.Externs;
}
else if (declarationSyntax.Kind() == SyntaxKind.NamespaceDeclaration)
{
......@@ -92,25 +93,38 @@ internal sealed class Imports
var diagnostics = new DiagnosticBag();
var compilation = binder.Compilation;
var externAliases = BuildExternAliases(externAliasDirectives, binder, diagnostics);
var usings = ArrayBuilder<NamespaceOrTypeAndUsingDirective>.GetInstance();
ImmutableDictionary<string, AliasAndUsingDirective>.Builder usingAliases = null;
if (usingDirectives.Count > 0)
{
// A binder that contains the extern aliases but not the usings. The resolution of the target of a using directive or alias
// should not make use of other peer usings.
var usingsBinder = binder.IsSubmissionClass ?
// Top-level usings in interactive code are resolved in the context of global namespace, w/o extern aliases:
new InContainerBinder(binder.Compilation.GlobalNamespace, new BuckStopsHereBinder(binder.Compilation)) :
new InContainerBinder(binder.Container, binder.Next,
new Imports(binder.Compilation, ImmutableDictionary<string, AliasAndUsingDirective>.Empty, ImmutableArray<NamespaceOrTypeAndUsingDirective>.Empty, externAliases, null));
Binder usingsBinder;
if (declarationSyntax.SyntaxTree.Options.Kind != SourceCodeKind.Regular)
{
usingsBinder = compilation.GetBinderFactory(declarationSyntax.SyntaxTree).GetImportsBinder(declarationSyntax, inUsing: true);
}
else
{
var imports = externAliases.Length == 0
? Empty
: new Imports(
compilation,
ImmutableDictionary<string, AliasAndUsingDirective>.Empty,
ImmutableArray<NamespaceOrTypeAndUsingDirective>.Empty,
externAliases,
diagnostics: null);
usingsBinder = new InContainerBinder(binder.Container, binder.Next, imports);
}
var uniqueUsings = PooledHashSet<NamespaceOrTypeSymbol>.GetInstance();
foreach (var usingDirective in usingDirectives)
{
binder.Compilation.RecordImport(usingDirective);
compilation.RecordImport(usingDirective);
if (usingDirective.Alias != null)
{
......@@ -219,12 +233,18 @@ internal sealed class Imports
diagnostics = null;
}
return new Imports(binder.Compilation, usingAliases.ToImmutableDictionaryOrEmpty(), usings.ToImmutableAndFree(), externAliases, diagnostics);
return new Imports(compilation, usingAliases.ToImmutableDictionaryOrEmpty(), usings.ToImmutableAndFree(), externAliases, diagnostics);
}
public static Imports FromGlobalUsings(CSharpCompilation compilation)
{
var usings = compilation.Options.Usings;
if (usings.Length == 0 && compilation.PreviousSubmission == null)
{
return Empty;
}
var diagnostics = new DiagnosticBag();
var usingsBinder = new InContainerBinder(compilation.GlobalNamespace, new BuckStopsHereBinder(compilation));
var boundUsings = ArrayBuilder<NamespaceOrTypeAndUsingDirective>.GetInstance();
......@@ -252,16 +272,124 @@ 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();
if (boundUsings.Count == 0)
{
boundUsings.Free();
return Empty;
}
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)
{
if (previousSubmissionImports == Empty)
{
return Empty;
}
Debug.Assert(previousSubmissionImports != null);
Debug.Assert(previousSubmissionImports._compilation.IsSubmission);
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,
......@@ -271,6 +399,30 @@ public static Imports FromGlobalUsings(CSharpCompilation compilation)
return new Imports(compilation, usingAliases, usings, externs, diagnostics: null);
}
/// <remarks>
/// Does not preserve diagnostics.
/// </remarks>
internal Imports Concat(Imports otherImports)
{
if (this == Empty)
{
return otherImports;
}
if (otherImports == Empty)
{
return this;
}
Debug.Assert(this._compilation == otherImports._compilation);
var usingAliases = this.UsingAliases.SetItems(otherImports.UsingAliases); // NB: SetItems, rather than AddRange
var usings = this.Usings.AddRange(otherImports.Usings).Distinct(UsingTargetComparer.Instance);
var externAliases = this.ExternAliases.AddRange(otherImports.ExternAliases).Distinct(ExternAliasNameComparer.Instance);
return new Imports(this._compilation, usingAliases, usings, externAliases, diagnostics: null);
}
private static ImmutableArray<AliasAndExternAliasDirective> BuildExternAliases(
SyntaxList<ExternAliasDirectiveSyntax> syntaxList,
InContainerBinder binder,
......@@ -319,7 +471,8 @@ private void MarkImportDirective(CSharpSyntaxNode directive, bool callerIsSemant
private static void MarkImportDirective(CSharpCompilation compilation, CSharpSyntaxNode directive, bool callerIsSemanticModel)
{
if (directive != null && compilation != null && !callerIsSemanticModel)
Debug.Assert(compilation != null); // If any directives are used, then there must be a compilation.
if (directive != null && !callerIsSemanticModel)
{
compilation.MarkImportDirectiveAsUsed(directive);
}
......@@ -365,6 +518,11 @@ internal void Complete(CancellationToken cancellationToken)
private void Validate()
{
if (this == Empty)
{
return;
}
DiagnosticBag semanticDiagnostics = _compilation.DeclarationDiagnostics;
// Check constraints within named aliases.
......@@ -483,6 +641,11 @@ internal bool IsUsingAlias(string name, bool callerIsSemanticModel)
bool diagnose,
ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
if (originalBinder.Flags.Includes(BinderFlags.InScriptUsing))
{
return;
}
bool callerIsSemanticModel = originalBinder.IsSemanticModelBinder;
foreach (var typeOrNamespace in usings)
......@@ -538,11 +701,19 @@ internal bool IsUsingAlias(string name, bool callerIsSemanticModel)
ArrayBuilder<MethodSymbol> methods,
string name,
int arity,
LookupOptions options,
bool callerIsSemanticModel)
LookupOptions options,
Binder originalBinder)
{
var binderFlags = originalBinder.Flags;
if (binderFlags.Includes(BinderFlags.InScriptUsing))
{
return;
}
Debug.Assert(methods.Count == 0);
bool callerIsSemanticModel = binderFlags.Includes(BinderFlags.SemanticModel);
// We need to avoid collecting multiple candidates for an extension method imported both through a namespace and a static class
// We will look for duplicates only if both of the following flags are set to true
bool seenNamespaceWithExtensionMethods = false;
......@@ -595,35 +766,45 @@ 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)
{
AddLookupSymbolsInfoInAliases(result, 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);
}
internal void AddLookupSymbolsInfoInAliases(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder)
{
foreach (var usingAlias in this.UsingAliases.Values)
{
var usingAliasSymbol = usingAlias.Alias;
var usingAliasTargetSymbol = usingAliasSymbol.GetAliasTarget(basesBeingResolved: null);
if (originalBinder.CanAddLookupSymbolInfo(usingAliasTargetSymbol, options, null))
{
result.AddSymbol(usingAliasSymbol, usingAliasSymbol.Name, 0);
}
AddAliasSymbolToResult(result, usingAlias.Alias, options, originalBinder);
}
if (this.ExternAliases != null)
foreach (var externAlias in this.ExternAliases)
{
foreach (var externAlias in this.ExternAliases)
{
var externAliasSymbol = externAlias.Alias;
var externAliasTargetSymbol = externAliasSymbol.GetAliasTarget(basesBeingResolved: null);
if (originalBinder.CanAddLookupSymbolInfo(externAliasTargetSymbol, options, null))
{
result.AddSymbol(externAliasSymbol, externAliasSymbol.Name, 0);
}
}
AddAliasSymbolToResult(result, externAlias.Alias, options, 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)
{
if (originalBinder.Flags.Includes(BinderFlags.InScriptUsing))
{
return;
}
Debug.Assert(!options.CanConsiderNamespaces());
// look in all using namespaces
......@@ -638,5 +819,39 @@ internal void AddLookupSymbolsInfoInAliases(Binder originalBinder, LookupSymbols
}
}
}
private class UsingTargetComparer : IEqualityComparer<NamespaceOrTypeAndUsingDirective>
{
public static readonly IEqualityComparer<NamespaceOrTypeAndUsingDirective> Instance = new UsingTargetComparer();
private UsingTargetComparer() { }
bool IEqualityComparer<NamespaceOrTypeAndUsingDirective>.Equals(NamespaceOrTypeAndUsingDirective x, NamespaceOrTypeAndUsingDirective y)
{
return x.NamespaceOrType.Equals(y.NamespaceOrType);
}
int IEqualityComparer<NamespaceOrTypeAndUsingDirective>.GetHashCode(NamespaceOrTypeAndUsingDirective obj)
{
return obj.NamespaceOrType.GetHashCode();
}
}
private class ExternAliasNameComparer : IEqualityComparer<AliasAndExternAliasDirective>
{
public static readonly IEqualityComparer<AliasAndExternAliasDirective> Instance = new ExternAliasNameComparer();
private ExternAliasNameComparer() { }
bool IEqualityComparer<AliasAndExternAliasDirective>.Equals(AliasAndExternAliasDirective x, AliasAndExternAliasDirective y)
{
return x.Alias.Name == y.Alias.Name;
}
int IEqualityComparer<AliasAndExternAliasDirective>.GetHashCode(AliasAndExternAliasDirective obj)
{
return obj.Alias.Name.GetHashCode();
}
}
}
}
// 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;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
......@@ -15,26 +16,22 @@ namespace Microsoft.CodeAnalysis.CSharp
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 readonly Func<ConsList<Symbol>, Imports> _computeImports;
private Imports _lazyImports;
private ImportChain _lazyImportChain;
private readonly bool _inUsing;
/// <summary>
/// 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);
Debug.Assert(declarationSyntax != null);
_declarationSyntax = declarationSyntax;
_container = container;
_allowStaticClassUsings = allowStaticClassUsings;
_inUsing = inUsing;
_computeImports = basesBeingResolved => Imports.FromSyntax(declarationSyntax, this, basesBeingResolved, inUsing);
}
/// <summary>
......@@ -43,25 +40,29 @@ 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
/// <summary>
/// Creates a binder with given import computation function.
/// </summary>
internal InContainerBinder(Binder next, Func<ConsList<Symbol>, Imports> computeImports)
: base(next)
{
get
{
return _container;
}
Debug.Assert(computeImports != null);
_container = null;
_computeImports = computeImports;
}
internal bool AllowStaticClassUsings
internal NamespaceOrTypeSymbol Container
{
get
{
return _allowStaticClassUsings;
return _container;
}
}
......@@ -70,14 +71,16 @@ internal Imports GetImports()
return GetImports(basesBeingResolved: null);
}
private Imports GetImports(ConsList<Symbol> basesBeingResolved)
internal Imports GetImports(ConsList<Symbol> basesBeingResolved)
{
if (_imports == null)
Debug.Assert(_lazyImports != null || _computeImports != null, "Have neither imports nor a way to compute them.");
if (_lazyImports == null)
{
Interlocked.CompareExchange(ref _imports, Imports.FromSyntax(_declarationSyntax, this, basesBeingResolved, _inUsing), null);
Interlocked.CompareExchange(ref _lazyImports, _computeImports(basesBeingResolved), null);
}
return _imports;
return _lazyImports;
}
internal override ImportChain ImportChain
......@@ -87,7 +90,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);
}
......@@ -110,9 +113,9 @@ internal override Symbol ContainingMemberOrLambda
}
}
internal bool IsSubmissionClass
private 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)
......@@ -139,28 +142,21 @@ internal override bool SupportsExtensionMethods
string name,
int arity,
LookupOptions options,
bool isCallerSemanticModel)
Binder originalBinder)
{
if (searchUsingsNotNamespace)
{
this.GetImports().LookupExtensionMethodsInUsings(methods, name, arity, options, isCallerSemanticModel);
this.GetImports().LookupExtensionMethodsInUsings(methods, name, arity, options, originalBinder);
}
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);
}
}
}
......@@ -179,7 +175,7 @@ internal override bool SupportsExtensionMethods
var imports = GetImports(basesBeingResolved);
// 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);
......@@ -203,18 +199,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);
}
}
......
// 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;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
internal sealed class InteractiveUsingsBinder : UsingsBinder
{
internal InteractiveUsingsBinder(Binder next)
: base(next)
{
}
protected override ImmutableArray<NamespaceOrTypeAndUsingDirective> GetConsolidatedUsings()
{
var currentSubmissionUsings = this.Compilation.GetSubmissionImports().Usings;
// find the first preceding non-empty submission (has InteractiveUsingsBinder):
CSharpCompilation previous = this.Compilation.PreviousSubmission;
InteractiveUsingsBinder previousBinder = null;
while (previous != null && previousBinder == null)
{
previousBinder = previous.GetInteractiveUsingsBinder();
previous = previous.PreviousSubmission;
}
if (previousBinder != null)
{
// TODO (tomat):
// optimization: do this only if additional references are added to the submission:
return RebindAndAddUsings(previousBinder.ConsolidatedUsings, currentSubmissionUsings);
}
return currentSubmissionUsings;
}
internal override TypeSymbol GetIteratorElementType(YieldStatementSyntax node, DiagnosticBag diagnostics)
{
diagnostics.Add(ErrorCode.ERR_IteratorInInteractive, node.Location);
return CreateErrorType();
}
/// <summary>
/// Returns a new list of usings with all namespace symbols replaced by namespace symbols updated from current compilation references.
/// </summary>
private ImmutableArray<NamespaceOrTypeAndUsingDirective> RebindAndAddUsings(
ImmutableArray<NamespaceOrTypeAndUsingDirective> usingsToRebind,
ImmutableArray<NamespaceOrTypeAndUsingDirective> usingsToAdd)
{
if (usingsToRebind.Length == 0)
{
return usingsToAdd;
}
int rebindCount = usingsToRebind.Length;
var result = new NamespaceOrTypeAndUsingDirective[rebindCount + usingsToAdd.Length];
var reversedQualifiedName = new List<string>();
int resultIndex = 0;
for (int usingIndex = 0; usingIndex < rebindCount; usingIndex++)
{
var symbol = usingsToRebind[usingIndex];
if (symbol.NamespaceOrType.Kind == SymbolKind.Namespace)
{
var namespaceSymbol = (NamespaceSymbol)symbol.NamespaceOrType;
Debug.Assert(!namespaceSymbol.IsGlobalNamespace);
reversedQualifiedName.Clear();
do
{
reversedQualifiedName.Add(namespaceSymbol.Name);
namespaceSymbol = namespaceSymbol.ContainingNamespace;
}
while (!namespaceSymbol.IsGlobalNamespace);
NamespaceSymbol newNamespaceSymbol = Compilation.GlobalNamespace;
for (int i = reversedQualifiedName.Count - 1; i >= 0; i--)
{
newNamespaceSymbol = newNamespaceSymbol.GetNestedNamespace(reversedQualifiedName[i]);
// new submissions can only add more members to namespaces, not remove them
Debug.Assert((object)newNamespaceSymbol != null);
}
symbol = new NamespaceOrTypeAndUsingDirective(newNamespaceSymbol, null);
}
result[resultIndex++] = symbol;
}
// Don't add usings that are already present in rebound usings. An error has been
// reported if there are duplicate usings within one submission, so we only need to
// check for duplicates in previous submissions. Note that usings within each submission
// are already distinct.
foreach (var usingToAdd in usingsToAdd)
{
// The number of usings is small so use linear search rather than a hash set.
if (!result.Any(n => Equals(n.NamespaceOrType, usingToAdd.NamespaceOrType)))
{
result[resultIndex++] = usingToAdd;
}
}
Array.Resize(ref result, resultIndex);
return result.AsImmutableOrNull();
}
}
}
// 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 System.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
internal class UsingsBinder : Binder
{
private ImmutableArray<NamespaceOrTypeAndUsingDirective> _lazyConsolidatedUsings;
internal UsingsBinder(Binder next, ImmutableArray<NamespaceOrTypeAndUsingDirective> usings = default(ImmutableArray<NamespaceOrTypeAndUsingDirective>))
: base(next)
{
_lazyConsolidatedUsings = usings;
}
internal ImmutableArray<NamespaceOrTypeAndUsingDirective> ConsolidatedUsings
{
get
{
if (_lazyConsolidatedUsings.IsDefault)
{
ImmutableInterlocked.InterlockedCompareExchange(
ref _lazyConsolidatedUsings, GetConsolidatedUsings(), default(ImmutableArray<NamespaceOrTypeAndUsingDirective>));
}
return _lazyConsolidatedUsings;
}
}
protected virtual ImmutableArray<NamespaceOrTypeAndUsingDirective> GetConsolidatedUsings()
{
throw ExceptionUtilities.Unreachable;
}
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(ConsolidatedUsings, 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(ConsolidatedUsings, this, 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)
{
foreach (var nsOrType in ConsolidatedUsings)
{
if (nsOrType.NamespaceOrType.Kind == SymbolKind.Namespace)
{
((NamespaceSymbol)nsOrType.NamespaceOrType).GetExtensionMethods(methods, name, arity, options);
}
}
}
}
}
}
......@@ -128,7 +128,6 @@
<Compile Include="Binder\Imports.cs" />
<Compile Include="Binder\InContainerBinder.cs" />
<Compile Include="Binder\InMethodBinder.cs" />
<Compile Include="Binder\InteractiveUsingsBinder.cs" />
<Compile Include="Binder\LocalBinderFactory.cs" />
<Compile Include="Binder\LocalInProgressBinder.cs" />
<Compile Include="Binder\LocalScopeBinder.cs" />
......@@ -188,7 +187,6 @@
<Compile Include="Binder\SwitchBinder.cs" />
<Compile Include="Binder\SimpleLocalScopeBinder.cs" />
<Compile Include="Binder\TypeofBinder.cs" />
<Compile Include="Binder\UsingsBinder.cs" />
<Compile Include="Binder\UsingStatementBinder.cs" />
<Compile Include="Binder\WhileBinder.cs" />
<Compile Include="Binder\WithClassTypeParametersBinder.cs" />
......
......@@ -46,6 +46,7 @@ public sealed partial class CSharpCompilation : Compilation
private readonly CSharpCompilationOptions _options;
private readonly Lazy<Imports> _globalImports;
private readonly Lazy<Imports> _previousSubmissionImports;
private readonly Lazy<AliasSymbol> _globalNamespaceAlias; // alias symbol used to resolve "global::".
private readonly Lazy<ImplicitNamedTypeSymbol> _scriptClass;
private readonly CSharpCompilation _previousSubmission;
......@@ -292,7 +293,8 @@ public override INamedTypeSymbol CreateErrorTypeSymbol(INamespaceOrTypeSymbol co
this.builtInOperators = new BuiltInOperators(this);
_scriptClass = new Lazy<ImplicitNamedTypeSymbol>(BindScriptClass);
_globalImports = new Lazy<Imports>(BindGlobalUsings);
_globalImports = new Lazy<Imports>(BindGlobalImports);
_previousSubmissionImports = new Lazy<Imports>(ExpandPreviousSubmissionImports);
_globalNamespaceAlias = new Lazy<AliasSymbol>(CreateGlobalNamespaceAlias);
_anonymousTypeManager = new AnonymousTypeManager(this);
this.LanguageVersion = CommonLanguageVersion(syntaxAndDeclarations.ExternalSyntaxTrees);
......@@ -1195,17 +1197,56 @@ private ImplicitNamedTypeSymbol BindScriptClass()
return namespaceOrType as ImplicitNamedTypeSymbol;
}
internal Imports GlobalImports
/// <summary>
/// Global imports (including those from previous submissions, if there are any).
/// </summary>
internal Imports GlobalImports => _globalImports.Value;
private Imports BindGlobalImports() => Imports.FromGlobalUsings(this);
/// <summary>
/// Imports declared by this submission (null if this isn't one).
/// </summary>
internal Imports SubmissionImports
{
get { return _globalImports.Value; }
get
{
if (!this.IsSubmission)
{
return null;
}
// A submission may be empty or comprised of a single script file.
var tree = _syntaxAndDeclarations.ExternalSyntaxTrees.SingleOrDefault();
if (tree == null)
{
return Imports.Empty;
}
var binder = GetBinderFactory(tree).GetImportsBinder((CSharpSyntaxNode)tree.GetRoot());
return binder.GetImports();
}
}
internal IEnumerable<NamespaceOrTypeSymbol> GlobalUsings
/// <summary>
/// Imports from all previous submissions.
/// </summary>
internal Imports PreviousSubmissionImports => _previousSubmissionImports.Value;
private Imports ExpandPreviousSubmissionImports()
{
get
if (!this.IsSubmission)
{
return null;
}
if (_previousSubmission == null)
{
return GlobalImports.Usings.Select(u => u.NamespaceOrType);
return Imports.Empty;
}
return Imports.ExpandPreviousSubmissionImports(_previousSubmission.PreviousSubmissionImports, this).Concat(
Imports.ExpandPreviousSubmissionImports(_previousSubmission.SubmissionImports, this));
}
internal AliasSymbol GlobalNamespaceAlias
......@@ -1658,30 +1699,6 @@ internal Imports GetImports(SingleNamespaceDeclaration declaration)
return GetBinderFactory(declaration.SyntaxReference.SyntaxTree).GetImportsBinder((CSharpSyntaxNode)declaration.SyntaxReference.GetSyntax()).GetImports();
}
internal Imports GetSubmissionImports()
{
return ((SourceNamespaceSymbol)SourceModule.GlobalNamespace).GetBoundImportsMerged().SingleOrDefault() ?? Imports.Empty;
}
internal InteractiveUsingsBinder GetInteractiveUsingsBinder()
{
Debug.Assert(IsSubmission);
// empty compilation:
if ((object)ScriptClass == null)
{
Debug.Assert(_syntaxAndDeclarations.ExternalSyntaxTrees.Length == 0);
return null;
}
return GetBinderFactory(_syntaxAndDeclarations.ExternalSyntaxTrees.Single()).GetInteractiveUsingsBinder();
}
private Imports BindGlobalUsings()
{
return Imports.FromGlobalUsings(this);
}
private AliasSymbol CreateGlobalNamespaceAlias()
{
return AliasSymbol.CreateGlobalNamespaceAlias(this.GlobalNamespace, new InContainerBinder(this.GlobalNamespace, new BuckStopsHereBinder(this)));
......@@ -2096,7 +2113,6 @@ 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))
{
// global imports diagnostics (specified via compilation options):
GlobalImports.Complete(cancellationToken);
SourceLocation location = null;
......
......@@ -3959,6 +3959,7 @@ internal static ImmutableArray<MethodSymbol> GetReducedAndFilteredMethodGroupSym
options = LookupOptions.Default;
}
binder = binder.WithAdditionalFlags(BinderFlags.SemanticModel);
foreach (var scope in new ExtensionMethodScopes(binder))
{
var extensionMethods = ArrayBuilder<MethodSymbol>.GetInstance();
......@@ -3968,7 +3969,7 @@ internal static ImmutableArray<MethodSymbol> GetReducedAndFilteredMethodGroupSym
name,
arity,
options,
isCallerSemanticModel: true);
originalBinder: binder);
foreach (var method in extensionMethods)
{
......
......@@ -45,7 +45,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
internal sealed class AliasSymbol : Symbol, IAliasSymbol
{
private readonly SyntaxToken _aliasName;
private readonly InContainerBinder _binder;
private readonly Binder _binder;
private SymbolCompletionState _state;
private NamespaceOrTypeSymbol _aliasTarget;
......@@ -56,7 +56,7 @@ internal sealed class AliasSymbol : Symbol, IAliasSymbol
private readonly bool _isExtern;
private DiagnosticBag _aliasTargetDiagnostics;
private AliasSymbol(InContainerBinder binder, NamespaceOrTypeSymbol target, SyntaxToken aliasName, ImmutableArray<Location> locations)
private AliasSymbol(Binder binder, NamespaceOrTypeSymbol target, SyntaxToken aliasName, ImmutableArray<Location> locations)
{
_aliasName = aliasName;
_locations = locations;
......@@ -65,20 +65,20 @@ private AliasSymbol(InContainerBinder binder, NamespaceOrTypeSymbol target, Synt
_state.NotePartComplete(CompletionPart.AliasTarget);
}
private AliasSymbol(InContainerBinder binder, SyntaxToken aliasName)
private AliasSymbol(Binder binder, SyntaxToken aliasName)
{
_aliasName = aliasName;
_locations = ImmutableArray.Create(aliasName.GetLocation());
_binder = binder;
}
internal AliasSymbol(InContainerBinder binder, UsingDirectiveSyntax syntax)
internal AliasSymbol(Binder binder, UsingDirectiveSyntax syntax)
: this(binder, syntax.Alias.Name.Identifier)
{
_aliasTargetName = syntax.Name;
}
internal AliasSymbol(InContainerBinder binder, ExternAliasDirectiveSyntax syntax)
internal AliasSymbol(Binder binder, ExternAliasDirectiveSyntax syntax)
: this(binder, syntax.Identifier)
{
_isExtern = true;
......@@ -86,17 +86,34 @@ internal AliasSymbol(InContainerBinder binder, ExternAliasDirectiveSyntax syntax
// For the purposes of SemanticModel, it is convenient to have an AliasSymbol for the "global" namespace that "global::" binds
// to. This alias symbol is returned only when binding "global::" (special case code).
internal static AliasSymbol CreateGlobalNamespaceAlias(NamespaceSymbol globalNamespace, InContainerBinder globalNamespaceBinder)
internal static AliasSymbol CreateGlobalNamespaceAlias(NamespaceSymbol globalNamespace, Binder globalNamespaceBinder)
{
SyntaxToken aliasName = SyntaxFactory.Identifier(SyntaxFactory.TriviaList(), SyntaxKind.GlobalKeyword, "global", "global", SyntaxFactory.TriviaList());
return new AliasSymbol(globalNamespaceBinder, globalNamespace, aliasName, ImmutableArray<Location>.Empty);
}
internal static AliasSymbol CreateCustomDebugInfoAlias(NamespaceOrTypeSymbol targetSymbol, SyntaxToken aliasToken, InContainerBinder binder)
internal static AliasSymbol CreateCustomDebugInfoAlias(NamespaceOrTypeSymbol targetSymbol, SyntaxToken aliasToken, Binder binder)
{
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
......@@ -303,7 +320,7 @@ private NamespaceSymbol ResolveExternAliasTarget(DiagnosticBag diagnostics)
return target;
}
private static NamespaceOrTypeSymbol ResolveAliasTarget(InContainerBinder binder, NameSyntax syntax, DiagnosticBag diagnostics, ConsList<Symbol> basesBeingResolved)
private static NamespaceOrTypeSymbol ResolveAliasTarget(Binder binder, NameSyntax syntax, DiagnosticBag diagnostics, ConsList<Symbol> basesBeingResolved)
{
var declarationBinder = binder.WithAdditionalFlags(BinderFlags.SuppressConstraintChecks | BinderFlags.SuppressObsoleteChecks);
return declarationBinder.BindNamespaceOrTypeSymbol(syntax, diagnostics, basesBeingResolved);
......
......@@ -36,10 +36,10 @@ class B : Z { }
var classB = (root.Members[1] as NamespaceDeclarationSyntax).Members[0] as TypeDeclarationSyntax;
var model = compilation.GetSemanticModel(tree);
var symbol = model.GetDeclaredSymbol(classB);
Assert.NotNull(symbol);
Assert.NotNull(symbol.BaseType);
Assert.Equal("Foo.Bar.B", symbol.ToTestDisplayString());
Assert.Equal("Foo.Bar.Script.C", symbol.BaseType.ToTestDisplayString());
var baseType = symbol?.BaseType;
Assert.NotNull(baseType);
Assert.Equal(TypeKind.Error, baseType.TypeKind);
Assert.Equal(LookupResultKind.Inaccessible, ((ErrorTypeSymbol)baseType).ResultKind); // Script class members are private.
}
[Fact]
......
......@@ -41,7 +41,7 @@ public void UsingStatic()
}
[WorkItem(5450, "https://github.com/dotnet/roslyn/issues/5450")]
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/5450")]
[Fact]
public void GlobalUsings()
{
var sub1 = CreateSubmission(
......@@ -64,7 +64,7 @@ public void GlobalUsings()
}
[WorkItem(4811, "https://github.com/dotnet/roslyn/issues/4811")]
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/4811")]
[Fact]
public void AliasCurrentSubmission()
{
const string source = @"
......@@ -92,7 +92,7 @@ class Type { }
}
[WorkItem(4811, "https://github.com/dotnet/roslyn/issues/4811")]
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/4811")]
[Fact]
public void AliasPreviousSubmission()
{
var sub1 = CreateSubmission("class A { }");
......@@ -192,7 +192,7 @@ public void AliasHiding()
}
[WorkItem(4811, "https://github.com/dotnet/roslyn/issues/4811")]
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/4811")]
[Fact]
public void UsingStaticCurrentSubmission()
{
const string source = @"
......@@ -211,7 +211,7 @@ class Type
}
[WorkItem(4811, "https://github.com/dotnet/roslyn/issues/4811")]
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/4811")]
[Fact]
public void UsingStaticPreviousSubmission()
{
var sub1 = CreateSubmission("class A { public static int AA; }");
......@@ -319,15 +319,15 @@ public class B{0} {{ }}
var options = TestOptions.DebugDll.WithUsings("B");
var sub1 = CreateSubmission("using A;", new[] { lib1 }, options);
var sub1 = CreateSubmission("using A; typeof(A1) == typeof(B1)", new[] { lib1 }, options);
sub1.VerifyDiagnostics();
var sub2 = CreateSubmission("typeof(A1) == typeof(A2) && typeof(B1) == typeof(B2)", new[] { lib1, lib2 }, options: options, previous: sub1);
var sub2 = CreateSubmission("typeof(A1) == typeof(B1) && typeof(A2) == typeof(B2)", new[] { lib1, lib2 }, options: options, previous: sub1);
sub2.VerifyDiagnostics();
}
[WorkItem(5423, "https://github.com/dotnet/roslyn/issues/5423")]
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/5423")]
[Fact]
void UsingsFromLoadedScript()
{
const string scriptSource = @"
......@@ -442,6 +442,96 @@ void GlobalUsingsToLoadedScript()
compilation.VerifyDiagnostics();
}
[WorkItem(4811, "https://github.com/dotnet/roslyn/issues/4811")]
[Fact]
public void ConsumePreviousSubmissionUsings_Valid()
{
const string libSource = @"
namespace NOuter
{
public class Test { }
namespace NInner
{
public static class COuter
{
public static void M() { }
public static class CInner
{
public static void N() { }
}
}
}
}
";
var lib = CreateCompilationWithMscorlib(libSource).EmitToImageReference();
var refs = new[] { lib };
var submissions = new[]
{
"using NOuter;",
"typeof(Test)",
"using NI = NOuter.NInner;",
"typeof(NI.COuter)",
"using static NI.COuter;",
"M()",
"using static NI.COuter.CInner;",
"N()",
};
CSharpCompilation prev = null;
foreach (var submission in submissions)
{
System.Console.WriteLine(submission);
var curr = CreateSubmission(submission, refs, previous: prev);
curr.VerifyDiagnostics();
prev = curr;
}
}
[Fact]
public void ConsumePreviousSubmissionUsings_Invalid()
{
const string libSource = @"
namespace NOuter
{
public class COuter { }
namespace NInner
{
public static class CInner
{
}
}
}
";
var lib = CreateCompilationWithMscorlib(libSource).EmitToImageReference();
var refs = new[] { lib };
CreateSubmission("using NInner;", refs, previous: CreateSubmission("using NOuter;", refs)).VerifyDiagnostics(
// (1,7): error CS0246: The type or namespace name 'NInner' could not be found (are you missing a using directive or an assembly reference?)
// using NInner;
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "NInner").WithArguments("NInner").WithLocation(1, 7));
CreateSubmission("using NI = NInner;", refs, previous: CreateSubmission("using NOuter;", refs)).VerifyDiagnostics(
// (1,12): error CS0246: The type or namespace name 'NInner' could not be found (are you missing a using directive or an assembly reference?)
// using NI = NInner;
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "NInner").WithArguments("NInner").WithLocation(1, 12));
CreateSubmission("using static COuter;", refs, previous: CreateSubmission("using NOuter;", refs)).VerifyDiagnostics(
// (1,14): error CS0246: The type or namespace name 'COuter' could not be found (are you missing a using directive or an assembly reference?)
// using static COuter;
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "COuter").WithArguments("COuter").WithLocation(1, 14));
CreateSubmission("using static NInner.CInner;", refs, previous: CreateSubmission("using NOuter;", refs)).VerifyDiagnostics(
// (1,14): error CS0246: The type or namespace name 'NInner' could not be found (are you missing a using directive or an assembly reference?)
// 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();
......
......@@ -533,7 +533,7 @@ public void CompilationChain_HostObjectMembersHidesGlobal()
public void CompilationChain_UsingNotHidingHostObjectMembers()
{
var result =
CSharpScript.RunAsync("using System;", globals: new C1()).
CSharpScript.RunAsync("using System;", OptionsWithFacades, globals: new C1()).
ContinueWith("Environment").
Result.ReturnValue;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册