提交 57d43f27 编写于 作者: A Andrew Casey

Stop exposing imports to #loaded files

Fixes #5423
上级 fc47157b
...@@ -270,6 +270,11 @@ internal virtual ImportChain ImportChain ...@@ -270,6 +270,11 @@ internal virtual ImportChain ImportChain
} }
} }
internal virtual Imports GetImports(ConsList<Symbol> basesBeingResolved)
{
return _next.GetImports(basesBeingResolved);
}
/// <summary> /// <summary>
/// The type containing the binding context /// The type containing the binding context
/// </summary> /// </summary>
......
...@@ -801,6 +801,12 @@ internal InContainerBinder VisitCompilationUnit(CompilationUnitSyntax compilatio ...@@ -801,6 +801,12 @@ internal InContainerBinder VisitCompilationUnit(CompilationUnitSyntax compilatio
// + script class members and using aliases // + script class members and using aliases
// //
bool isSubmissionTree = compilation.IsSubmissionSyntaxTree(compilationUnit.SyntaxTree);
if (!isSubmissionTree)
{
result = result.WithAdditionalFlags(BinderFlags.InLoadedSyntaxTree);
}
// This is declared here so it can be captured. It's initialized below. // This is declared here so it can be captured. It's initialized below.
InContainerBinder scriptClassBinder = null; InContainerBinder scriptClassBinder = null;
...@@ -814,7 +820,8 @@ internal InContainerBinder VisitCompilationUnit(CompilationUnitSyntax compilatio ...@@ -814,7 +820,8 @@ internal InContainerBinder VisitCompilationUnit(CompilationUnitSyntax compilatio
// NB: This binder has a full Imports object, but only the non-alias imports are // NB: This binder has a full Imports object, but only the non-alias imports are
// ever consumed. Aliases are actually checked in scriptClassBinder (below). // ever consumed. Aliases are actually checked in scriptClassBinder (below).
result = compilation.PreviousSubmission == null // Note: #loaded trees don't consume previous submission imports.
result = compilation.PreviousSubmission == null || !isSubmissionTree
? new InContainerBinder(result, basesBeingResolved => scriptClassBinder.GetImports(basesBeingResolved)) ? new InContainerBinder(result, basesBeingResolved => scriptClassBinder.GetImports(basesBeingResolved))
: new InContainerBinder(result, basesBeingResolved => : new InContainerBinder(result, basesBeingResolved =>
compilation.GetPreviousSubmissionImports().Concat(scriptClassBinder.GetImports(basesBeingResolved))); compilation.GetPreviousSubmissionImports().Concat(scriptClassBinder.GetImports(basesBeingResolved)));
......
...@@ -93,6 +93,11 @@ internal enum BinderFlags : uint ...@@ -93,6 +93,11 @@ internal enum BinderFlags : uint
/// </summary> /// </summary>
InScriptUsing = 1 << 27, InScriptUsing = 1 << 27,
/// <summary>
/// In a file that has been included in the compilation via #load.
/// </summary>
InLoadedSyntaxTree = 1 << 28,
// Groups // Groups
AllClearedAtExecutableCodeBoundary = InLockBody | InCatchBlock | InCatchFilter | InFinallyBlock | InTryBlockOfTryCatch | InNestedFinallyBlock, AllClearedAtExecutableCodeBoundary = InLockBody | InCatchBlock | InCatchFilter | InFinallyBlock | InTryBlockOfTryCatch | InNestedFinallyBlock,
......
...@@ -246,7 +246,24 @@ private void LookupMembersInSubmissions(LookupResult result, TypeSymbol submissi ...@@ -246,7 +246,24 @@ private void LookupMembersInSubmissions(LookupResult result, TypeSymbol submissi
var isCurrentSubmission = submission == Compilation; var isCurrentSubmission = submission == Compilation;
var considerUsings = !(isCurrentSubmission && this.Flags.Includes(BinderFlags.InScriptUsing)); var considerUsings = !(isCurrentSubmission && this.Flags.Includes(BinderFlags.InScriptUsing));
var submissionImports = considerUsings ? submission.GetSubmissionImports() : Imports.Empty;
Imports submissionImports;
if (!considerUsings)
{
submissionImports = Imports.Empty;
}
else if (!this.Flags.Includes(BinderFlags.InLoadedSyntaxTree))
{
submissionImports = submission.GetSubmissionImports();
}
else if (isCurrentSubmission)
{
submissionImports = this.GetImports(basesBeingResolved);
}
else
{
submissionImports = Imports.Empty;
}
// If a viable using alias and a matching member are both defined in the submission an error is reported elsewhere. // 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. // Ignore the member in such case.
......
...@@ -35,6 +35,11 @@ internal override ImportChain ImportChain ...@@ -35,6 +35,11 @@ internal override ImportChain ImportChain
} }
} }
internal override Imports GetImports(ConsList<Symbol> basesBeingResolved)
{
return Imports.Empty;
}
protected override SourceLocalSymbol LookupLocal(SyntaxToken nameToken) protected override SourceLocalSymbol LookupLocal(SyntaxToken nameToken)
{ {
return null; return null;
......
...@@ -66,12 +66,7 @@ internal NamespaceOrTypeSymbol Container ...@@ -66,12 +66,7 @@ internal NamespaceOrTypeSymbol Container
} }
} }
internal Imports GetImports() internal override Imports GetImports(ConsList<Symbol> basesBeingResolved)
{
return GetImports(basesBeingResolved: null);
}
internal Imports GetImports(ConsList<Symbol> basesBeingResolved)
{ {
Debug.Assert(_lazyImports != null || _computeImports != null, "Have neither imports nor a way to compute them."); Debug.Assert(_lazyImports != null || _computeImports != null, "Have neither imports nor a way to compute them.");
...@@ -92,7 +87,7 @@ internal override ImportChain ImportChain ...@@ -92,7 +87,7 @@ internal override ImportChain ImportChain
ImportChain importChain = this.Next.ImportChain; ImportChain importChain = this.Next.ImportChain;
if ((object)_container == null || _container.Kind == SymbolKind.Namespace) if ((object)_container == null || _container.Kind == SymbolKind.Namespace)
{ {
importChain = new ImportChain(GetImports(), importChain); importChain = new ImportChain(GetImports(basesBeingResolved: null), importChain);
} }
Interlocked.CompareExchange(ref _lazyImportChain, importChain, null); Interlocked.CompareExchange(ref _lazyImportChain, importChain, null);
...@@ -146,7 +141,7 @@ internal override bool SupportsExtensionMethods ...@@ -146,7 +141,7 @@ internal override bool SupportsExtensionMethods
{ {
if (searchUsingsNotNamespace) if (searchUsingsNotNamespace)
{ {
this.GetImports().LookupExtensionMethodsInUsings(methods, name, arity, options, originalBinder); this.GetImports(basesBeingResolved: null).LookupExtensionMethodsInUsings(methods, name, arity, options, originalBinder);
} }
else if (_container?.Kind == SymbolKind.Namespace) else if (_container?.Kind == SymbolKind.Namespace)
{ {
......
...@@ -1200,6 +1200,13 @@ private ImplicitNamedTypeSymbol BindScriptClass() ...@@ -1200,6 +1200,13 @@ private ImplicitNamedTypeSymbol BindScriptClass()
return namespaceOrType as ImplicitNamedTypeSymbol; return namespaceOrType as ImplicitNamedTypeSymbol;
} }
internal bool IsSubmissionSyntaxTree(SyntaxTree tree)
{
Debug.Assert(tree != null);
Debug.Assert(!this.IsSubmission || _syntaxAndDeclarations.ExternalSyntaxTrees.Length <= 1);
return this.IsSubmission && tree == _syntaxAndDeclarations.ExternalSyntaxTrees.SingleOrDefault();
}
/// <summary> /// <summary>
/// Global imports (including those from previous submissions, if there are any). /// Global imports (including those from previous submissions, if there are any).
/// </summary> /// </summary>
...@@ -1223,7 +1230,7 @@ internal Imports GetSubmissionImports() ...@@ -1223,7 +1230,7 @@ internal Imports GetSubmissionImports()
} }
var binder = GetBinderFactory(tree).GetImportsBinder((CSharpSyntaxNode)tree.GetRoot()); var binder = GetBinderFactory(tree).GetImportsBinder((CSharpSyntaxNode)tree.GetRoot());
return binder.GetImports(); return binder.GetImports(basesBeingResolved: null);
} }
/// <summary> /// <summary>
...@@ -1691,7 +1698,7 @@ internal Binder GetBinder(CSharpSyntaxNode syntax) ...@@ -1691,7 +1698,7 @@ internal Binder GetBinder(CSharpSyntaxNode syntax)
/// </summary> /// </summary>
internal Imports GetImports(SingleNamespaceDeclaration declaration) internal Imports GetImports(SingleNamespaceDeclaration declaration)
{ {
return GetBinderFactory(declaration.SyntaxReference.SyntaxTree).GetImportsBinder((CSharpSyntaxNode)declaration.SyntaxReference.GetSyntax()).GetImports(); return GetBinderFactory(declaration.SyntaxReference.SyntaxTree).GetImportsBinder((CSharpSyntaxNode)declaration.SyntaxReference.GetSyntax()).GetImports(basesBeingResolved: null);
} }
private AliasSymbol CreateGlobalNamespaceAlias() private AliasSymbol CreateGlobalNamespaceAlias()
......
...@@ -1635,7 +1635,7 @@ public override ILabelSymbol GetDeclaredSymbol(SwitchLabelSyntax declarationSynt ...@@ -1635,7 +1635,7 @@ public override ILabelSymbol GetDeclaredSymbol(SwitchLabelSyntax declarationSynt
} }
InContainerBinder binder = _binderFactory.GetImportsBinder(declarationSyntax.Parent); InContainerBinder binder = _binderFactory.GetImportsBinder(declarationSyntax.Parent);
var imports = binder.GetImports(); var imports = binder.GetImports(basesBeingResolved: null);
var alias = imports.UsingAliases[declarationSyntax.Alias.Name.Identifier.ValueText]; var alias = imports.UsingAliases[declarationSyntax.Alias.Name.Identifier.ValueText];
if ((object)alias.Alias == null) if ((object)alias.Alias == null)
...@@ -1666,7 +1666,7 @@ public override IAliasSymbol GetDeclaredSymbol(ExternAliasDirectiveSyntax declar ...@@ -1666,7 +1666,7 @@ public override IAliasSymbol GetDeclaredSymbol(ExternAliasDirectiveSyntax declar
CheckSyntaxNode(declarationSyntax); CheckSyntaxNode(declarationSyntax);
var binder = _binderFactory.GetImportsBinder(declarationSyntax.Parent); var binder = _binderFactory.GetImportsBinder(declarationSyntax.Parent);
var imports = binder.GetImports(); var imports = binder.GetImports(basesBeingResolved: null);
// TODO: If this becomes a bottleneck, put the extern aliases in a dictionary, as for using aliases. // TODO: If this becomes a bottleneck, put the extern aliases in a dictionary, as for using aliases.
foreach (var alias in imports.ExternAliases) foreach (var alias in imports.ExternAliases)
......
...@@ -106,7 +106,7 @@ public void ConcatCollidingExternAliases() ...@@ -106,7 +106,7 @@ public void ConcatCollidingExternAliases()
var tree = comp.SyntaxTrees.Single(); var tree = comp.SyntaxTrees.Single();
var binder = comp.GetBinderFactory(tree).GetImportsBinder((CSharpSyntaxNode)tree.GetRoot(), inUsing: false); var binder = comp.GetBinderFactory(tree).GetImportsBinder((CSharpSyntaxNode)tree.GetRoot(), inUsing: false);
var scratchImports = binder.GetImports(); var scratchImports = binder.GetImports(basesBeingResolved: null);
var scratchExternAliases = scratchImports.ExternAliases; var scratchExternAliases = scratchImports.ExternAliases;
Assert.Equal(2, scratchExternAliases.Length); Assert.Equal(2, scratchExternAliases.Length);
...@@ -145,7 +145,7 @@ private static Imports[] GetImports(params string[] sources) ...@@ -145,7 +145,7 @@ private static Imports[] GetImports(params string[] sources)
var factories = trees.Select(tree => comp.GetBinderFactory(tree)); var factories = trees.Select(tree => comp.GetBinderFactory(tree));
var binders = factories.Select(factory => factory.GetImportsBinder((CSharpSyntaxNode)factory.SyntaxTree.GetRoot(), inUsing: false)); var binders = factories.Select(factory => factory.GetImportsBinder((CSharpSyntaxNode)factory.SyntaxTree.GetRoot(), inUsing: false));
var imports = binders.Select(binder => binder.GetImports()); var imports = binders.Select(binder => binder.GetImports(basesBeingResolved: null));
Assert.DoesNotContain(Imports.Empty, imports); Assert.DoesNotContain(Imports.Empty, imports);
return imports.ToArray(); return imports.ToArray();
} }
......
...@@ -373,17 +373,43 @@ class C { } ...@@ -373,17 +373,43 @@ class C { }
} }
[WorkItem(5423, "https://github.com/dotnet/roslyn/issues/5423")] [WorkItem(5423, "https://github.com/dotnet/roslyn/issues/5423")]
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/5423")] [Fact]
void UsingsToLoadedScript() void UsingsToLoadedScript()
{ {
const string scriptSource = @" const string scriptSource = @"
using System.Collections.Generic;
using AL = System.Collections.ArrayList;
using static System.Math;
class D { }
System.Type t; System.Type t;
// Previous submission
GetCommandLineArgs(); // using static not exposed
t = typeof(StringBuilder); // using not exposed
t = typeof(P); // using alias not exposed
t = typeof(B); // declaration exposed
// Current submission
GetTempPath(); // using static not exposed GetTempPath(); // using static not exposed
t = typeof(File); // using not exposed t = typeof(File); // using not exposed
t = typeof(F); // using alias not exposed t = typeof(F); // using alias not exposed
t = typeof(C); // declaration exposed t = typeof(C); // declaration exposed
// Current file - all available
Sin(1);
t = typeof(List<int>);
t = typeof(AL);
t = typeof(D);
";
const string previousSubmissionSource = @"
using static System.Environment;
using System.Text;
using P = System.IO.Path;
class B { }
"; ";
const string submissionSource = @" const string submissionSource = @"
...@@ -403,18 +429,33 @@ class C { } ...@@ -403,18 +429,33 @@ class C { }
var compilation = CreateSubmission( var compilation = CreateSubmission(
submissionSource, submissionSource,
options: TestOptions.DebugDll.WithSourceReferenceResolver(resolver)); options: TestOptions.DebugDll.WithSourceReferenceResolver(resolver),
previous: CreateSubmission(previousSubmissionSource));
compilation.VerifyDiagnostics( compilation.VerifyDiagnostics(
// a.csx(4,1): error CS0103: The name 'GetTempPath' does not exist in the current context // Previous submission
// a.csx(11,1): error CS0103: The name 'GetCommandLineArgs' does not exist in the current context
// GetCommandLineArgs(); // using static not exposed
Diagnostic(ErrorCode.ERR_NameNotInContext, "GetCommandLineArgs").WithArguments("GetCommandLineArgs").WithLocation(11, 1),
// a.csx(12,12): error CS0246: The type or namespace name 'StringBuilder' could not be found (are you missing a using directive or an assembly reference?)
// t = typeof(StringBuilder); // using not exposed
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "StringBuilder").WithArguments("StringBuilder").WithLocation(12, 12),
// a.csx(13,12): error CS0246: The type or namespace name 'P' could not be found (are you missing a using directive or an assembly reference?)
// t = typeof(P); // using alias not exposed
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "P").WithArguments("P").WithLocation(13, 12),
// Current submission
// a.csx(17,1): error CS0103: The name 'GetTempPath' does not exist in the current context
// GetTempPath(); // using static not exposed // GetTempPath(); // using static not exposed
Diagnostic(ErrorCode.ERR_NameNotInContext, "GetTempPath").WithArguments("GetTempPath").WithLocation(4, 1), Diagnostic(ErrorCode.ERR_NameNotInContext, "GetTempPath").WithArguments("GetTempPath").WithLocation(17, 1),
// a.csx(5,12): error CS0246: The type or namespace name 'File' could not be found (are you missing a using directive or an assembly reference?) // a.csx(18,12): error CS0246: The type or namespace name 'File' could not be found (are you missing a using directive or an assembly reference?)
// t = typeof(File); // using not exposed // t = typeof(File); // using not exposed
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "File").WithArguments("File").WithLocation(5, 12), Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "File").WithArguments("File").WithLocation(18, 12),
// a.csx(6,12): error CS0246: The type or namespace name 'F' could not be found (are you missing a using directive or an assembly reference?) // a.csx(19,12): error CS0246: The type or namespace name 'F' could not be found (are you missing a using directive or an assembly reference?)
// t = typeof(F); // using alias not exposed // t = typeof(F); // using alias not exposed
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "F").WithArguments("F").WithLocation(6, 12)); Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "F").WithArguments("F").WithLocation(19, 12));
} }
[Fact] [Fact]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册