diff --git a/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs index b8d32d13938e6..5e99a4d7e175c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs @@ -729,7 +729,16 @@ internal NamedTypeSymbol GetTopLevelTypeByMetadataName( "Never include references for a non-source assembly, because they don't know about aliases."); var assemblies = ArrayBuilder.GetInstance(); - DeclaringCompilation.GetUnaliasedReferencedAssemblies(assemblies); + + // ignore reference aliases if searching for a type from a specific assembly: + if (assemblyOpt != null) + { + assemblies.AddRange(DeclaringCompilation.GetBoundReferenceManager().ReferencedAssemblies); + } + else + { + DeclaringCompilation.GetUnaliasedReferencedAssemblies(assemblies); + } // Lookup in references foreach (var assembly in assemblies) diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/ReferenceManagerTests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/ReferenceManagerTests.cs index 303701c226cd9..67b67c278713d 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/ReferenceManagerTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/ReferenceManagerTests.cs @@ -19,13 +19,7 @@ public class ReferenceManagerTests : CSharpTestBase { private static readonly CSharpCompilationOptions s_signedDll = TestOptions.ReleaseDll.WithCryptoPublicKey(TestResources.TestKeys.PublicKey_ce65828c82a341f2); - - private static IEnumerable GetAssemblyAliases(Compilation compilation) - { - return compilation.GetBoundReferenceManager().GetReferencedAssemblyAliases(). - Select(t => $"{t.Item1.Identity.Name}{(t.Item2.IsEmpty ? "" : ": " + string.Join(",", t.Item2))}"); - } - + [Fact] public void WinRtCompilationReferences() { @@ -2202,12 +2196,11 @@ public void ReferenceDirective_RecursiveReferenceWithNoAliases() c.VerifyDiagnostics(); - AssertEx.Equal(new[] - { + c.VerifyAssemblyAliases( "mscorlib", "B: X,global", "A" - }, GetAssemblyAliases(c)); + ); } [Fact] @@ -2234,12 +2227,10 @@ public void ReferenceDirective_NonRecursiveReferenceWithNoAliases() // new B() Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "B").WithArguments("B")); - AssertEx.Equal(new[] - { + c.VerifyAssemblyAliases( "mscorlib", "B: X", - "A" - }, GetAssemblyAliases(c)); + "A"); } [Fact] @@ -2272,12 +2263,10 @@ public class P c.VerifyDiagnostics(); - AssertEx.Equal(new[] - { + c.VerifyAssemblyAliases( "B: X,Y", "A: global,Y", - "mscorlib: global,Y" - }, GetAssemblyAliases(c)); + "mscorlib: global,Y"); } [Fact] @@ -2310,12 +2299,10 @@ public class P c.VerifyDiagnostics(); - AssertEx.Equal(new[] - { + c.VerifyAssemblyAliases( "B: X,Y", "A: global,Y", - "mscorlib: global,Y" - }, GetAssemblyAliases(c)); + "mscorlib: global,Y"); } [Fact] @@ -2350,12 +2337,10 @@ public class P c.VerifyDiagnostics(); - AssertEx.Equal(new[] - { + c.VerifyAssemblyAliases( "B: X,Y", "A: global,Y", - "mscorlib: global,Y" - }, GetAssemblyAliases(c)); + "mscorlib: global,Y"); } [Fact] @@ -2391,13 +2376,11 @@ public class P c.VerifyDiagnostics(); - AssertEx.Equal(new[] - { + c.VerifyAssemblyAliases( "B: X,Y,Y,Z", "A: Y,Y,Z", "D: Z", - "mscorlib: global,Y,Y,Z" - }, GetAssemblyAliases(c)); + "mscorlib: global,Y,Y,Z"); } [Fact] diff --git a/src/Compilers/Core/Portable/ReferenceManager/CommonReferenceManager.Resolution.cs b/src/Compilers/Core/Portable/ReferenceManager/CommonReferenceManager.Resolution.cs index add05da2d8bde..7b16a18844fcc 100644 --- a/src/Compilers/Core/Portable/ReferenceManager/CommonReferenceManager.Resolution.cs +++ b/src/Compilers/Core/Portable/ReferenceManager/CommonReferenceManager.Resolution.cs @@ -790,7 +790,7 @@ private static PortableExecutableReference ResolveReferenceDirective(string refe // checked earlier: Debug.Assert(compilation.Options.MetadataReferenceResolver != null); - var references = compilation.Options.MetadataReferenceResolver.ResolveReference(reference, basePath, MetadataReferenceProperties.Assembly); + var references = compilation.Options.MetadataReferenceResolver.ResolveReference(reference, basePath, MetadataReferenceProperties.Assembly.WithRecursiveAliases(true)); if (references.IsDefaultOrEmpty) { return null; diff --git a/src/Interactive/EditorFeatures/Core/Extensibility/Interactive/InteractiveEvaluator.cs b/src/Interactive/EditorFeatures/Core/Extensibility/Interactive/InteractiveEvaluator.cs index 0c8cfa2ef48f5..724bd79f6daab 100644 --- a/src/Interactive/EditorFeatures/Core/Extensibility/Interactive/InteractiveEvaluator.cs +++ b/src/Interactive/EditorFeatures/Core/Extensibility/Interactive/InteractiveEvaluator.cs @@ -205,7 +205,7 @@ private void ProcessStarting(bool initialize) var metadataService = _workspace.CurrentSolution.Services.MetadataService; var mscorlibRef = metadataService.GetReference(typeof(object).Assembly.Location, MetadataReferenceProperties.Assembly); - var interactiveHostObjectRef = metadataService.GetReference(typeof(InteractiveScriptGlobals).Assembly.Location, MetadataReferenceProperties.Assembly); + var interactiveHostObjectRef = metadataService.GetReference(typeof(InteractiveScriptGlobals).Assembly.Location, Script.HostAssemblyReferenceProperties); _references = ImmutableHashSet.Create(mscorlibRef, interactiveHostObjectRef); _rspImports = ImmutableArray.Empty; diff --git a/src/Interactive/HostTest/InteractiveHostTests.cs b/src/Interactive/HostTest/InteractiveHostTests.cs index 28bb5ca211d21..656e6fde9175f 100644 --- a/src/Interactive/HostTest/InteractiveHostTests.cs +++ b/src/Interactive/HostTest/InteractiveHostTests.cs @@ -938,6 +938,18 @@ public void ReferenceDirectives() Assert.Equal("1\r\n2\r\n", output); } + [Fact] + public void Script_NoHostNamespaces() + { + Execute("nameof(Microsoft.CodeAnalysis)"); + + AssertEx.AssertEqualToleratingWhitespaceDifferences(@" +(1,8): error CS0234: The type or namespace name 'CodeAnalysis' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?)", + ReadErrorOutputToEnd()); + + Assert.Equal("", ReadOutputToEnd()); + } + [Fact] public void ExecutesOnStaThread() { diff --git a/src/Scripting/CSharpTest/CommandLineRunnerTests.cs b/src/Scripting/CSharpTest/CommandLineRunnerTests.cs index b955ce77f3515..285ff4e76f17c 100644 --- a/src/Scripting/CSharpTest/CommandLineRunnerTests.cs +++ b/src/Scripting/CSharpTest/CommandLineRunnerTests.cs @@ -357,6 +357,25 @@ public void Script_BadUsings() ", runner.Console.Out.ToString()); } + [Fact] + public void Script_NoHostNamespaces() + { + var runner = CreateRunner(input: "nameof(Microsoft.CodeAnalysis)"); + + runner.RunInteractive(); + + AssertEx.AssertEqualToleratingWhitespaceDifferences( +$@"Microsoft (R) Visual C# Interactive Compiler version {CompilerVersion} +Copyright (C) Microsoft Corporation. All rights reserved. + +Type ""#help"" for more information. +> nameof(Microsoft.CodeAnalysis) +«Red» +(1,8): error CS0234: The type or namespace name 'CodeAnalysis' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?) +«Gray» +> ", runner.Console.Out.ToString()); + } + [Fact] public void SourceSearchPaths1() { diff --git a/src/Scripting/CSharpTest/InteractiveSessionTests.cs b/src/Scripting/CSharpTest/InteractiveSessionTests.cs index fbd898d3f86c8..27aba2af31b77 100644 --- a/src/Scripting/CSharpTest/InteractiveSessionTests.cs +++ b/src/Scripting/CSharpTest/InteractiveSessionTests.cs @@ -10,7 +10,9 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Scripting.Hosting; using Microsoft.CodeAnalysis.Scripting.Test; +using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -1442,6 +1444,189 @@ public void HostObjectInRootNamespace() Assert.Equal(1, r1.Result); } + [Fact] + public void HostObjectAssemblyReference1() + { + var scriptCompilation = CSharpScript.Create( + "nameof(Microsoft.CodeAnalysis.Scripting)", + globalsType: typeof(CommandLineScriptGlobals)).GetCompilation(); + + scriptCompilation.VerifyDiagnostics( + // (1,8): error CS0234: The type or namespace name 'CodeAnalysis' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?) + Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "Microsoft.CodeAnalysis").WithArguments("CodeAnalysis", "Microsoft")); + + scriptCompilation.VerifyAssemblyAliases( + "mscorlib: global,", + "Microsoft.CodeAnalysis.Scripting: ", + "System.Collections.Immutable: ,", + "Microsoft.CodeAnalysis: ,", + "System.Diagnostics.Tools: ,", + "System.Resources.ResourceManager: ,", + "System.Console: ,", + "System.Diagnostics.StackTrace: ,", + "System.IO.FileSystem: ,", + "System.Linq: ,", + "System.Text.Encoding: ,", + "System.IO.FileSystem.Primitives: ,", + "System.Reflection.Extensions: ,", + "System.Core: ,", + "System: ,", + "System.Xml: ,", + "System.Numerics: ,", + "System.Security: ,", + "System.Data.SqlXml: ,", + "System.Configuration: ,", + "System.Runtime: ,", + "System.Diagnostics.Debug: ,", + "System.Runtime.InteropServices: ,", + "System.Reflection.Metadata: ,", + "System.IO: ,", + "System.Collections: ,", + "System.Threading.Tasks: ,", + "System.Reflection.Primitives: ,", + "System.Reflection: ,", + "System.Globalization: ,", + "System.Runtime.Extensions: ,", + "System.Runtime.Numerics: ,", + "System.Runtime.Serialization.Json: ,", + "System.Collections.Concurrent: ,", + "System.Xml.ReaderWriter: ,", + "System.Xml.XDocument: ,", + "System.Dynamic.Runtime: ,", + "System.Threading: ,", + "System.Text.Encoding.Extensions: ,", + "System.Xml.Linq: ,", + "System.Runtime.Serialization: ,", + "System.ServiceModel.Internals: ,", + "SMDiagnostics: ,", + "System.ComponentModel.Composition: ,"); + } + + [Fact] + public void HostObjectAssemblyReference2() + { + var scriptCompilation = CSharpScript.Create( + "typeof(Microsoft.CodeAnalysis.Scripting.Script)", + options: ScriptOptions.Default.WithReferences(typeof(CSharpScript).GetTypeInfo().Assembly), + globalsType: typeof(CommandLineScriptGlobals)).GetCompilation(); + + scriptCompilation.VerifyDiagnostics(); + + scriptCompilation.VerifyAssemblyAliases( + "mscorlib: global,", + "Microsoft.CodeAnalysis.Scripting: ,global", + "Microsoft.CodeAnalysis.Scripting.CSharp", + "Microsoft.CodeAnalysis.CSharp: ,global", + "Microsoft.CodeAnalysis: ,,global", + "System.Collections.Immutable: ,,global", + "System.Diagnostics.Tools: ,,global", + "System.Resources.ResourceManager: ,,global", + "System.Text.Encoding: ,,global", + "System.AppContext: ,global", + "System.Reflection.Extensions: ,,global", + "System: ,,global", + "System.Configuration: ,,global", + "System.Xml: ,,global", + "System.Data.SqlXml: ,,global", + "System.Security: ,,global", + "System.Core: ,,global", + "System.Numerics: ,,global", + "System.Runtime: ,,global", + "System.Diagnostics.Debug: ,,global", + "System.Collections: ,,global", + "System.Linq: ,,global", + "System.Runtime.Extensions: ,,global", + "System.Globalization: ,,global", + "System.Threading: ,,global", + "System.ComponentModel.Composition: ,,global", + "System.Runtime.InteropServices: ,,global", + "System.Reflection.Metadata: ,,global", + "System.IO: ,,global", + "System.Threading.Tasks: ,,global", + "System.Reflection.Primitives: ,,global", + "System.Reflection: ,,global", + "System.Runtime.Numerics: ,,global", + "System.Runtime.Serialization.Json: ,,global", + "System.Collections.Concurrent: ,,global", + "System.Xml.ReaderWriter: ,,global", + "System.Xml.XDocument: ,,global", + "System.Dynamic.Runtime: ,,global", + "System.Text.Encoding.Extensions: ,,global", + "System.Xml.Linq: ,,global", + "System.Runtime.Serialization: ,,global", + "System.ServiceModel.Internals: ,,global", + "SMDiagnostics: ,,global", + "System.Linq.Expressions: ,global", + "System.Threading.Tasks.Parallel: ,global", + "System.Console: ,,global", + "System.Diagnostics.StackTrace: ,,global", + "System.IO.FileSystem: ,,global", + "System.IO.FileSystem.Primitives: ,,global"); + } + + [Fact] + public void HostObjectAssemblyReference3() + { + string source = $@" +#r ""{typeof(CSharpScript).GetTypeInfo().Assembly.ManifestModule.FullyQualifiedName}"" +typeof(Microsoft.CodeAnalysis.Scripting.Script) +"; + var scriptCompilation = CSharpScript.Create(source, globalsType: typeof(CommandLineScriptGlobals)).GetCompilation(); + + scriptCompilation.VerifyDiagnostics(); + + scriptCompilation.VerifyAssemblyAliases( + "Microsoft.CodeAnalysis.Scripting.CSharp", + "mscorlib: global,", + "Microsoft.CodeAnalysis.Scripting: global,", + "System.Collections.Immutable: ,global,", + "Microsoft.CodeAnalysis: ,global,", + "System.Diagnostics.Tools: ,global,", + "System.Resources.ResourceManager: ,global,", + "System.Console: ,global,", + "System.Diagnostics.StackTrace: ,global,", + "System.IO.FileSystem: ,global,", + "System.Linq: ,global,", + "System.Text.Encoding: ,global,", + "System.IO.FileSystem.Primitives: ,global,", + "System.Reflection.Extensions: ,global,", + "System.Core: ,global,", + "System: ,global,", + "System.Xml: ,global,", + "System.Numerics: ,global,", + "System.Security: ,global,", + "System.Data.SqlXml: ,global,", + "System.Configuration: ,global,", + "System.Runtime: ,global,", + "System.Diagnostics.Debug: ,global,", + "System.Runtime.InteropServices: ,global,", + "System.Reflection.Metadata: ,global,", + "System.IO: ,global,", + "System.Collections: ,global,", + "System.Threading.Tasks: ,global,", + "System.Reflection.Primitives: ,global,", + "System.Reflection: ,global,", + "System.Globalization: ,global,", + "System.Runtime.Extensions: ,global,", + "System.Runtime.Numerics: ,global,", + "System.Runtime.Serialization.Json: ,global,", + "System.Collections.Concurrent: ,global,", + "System.Xml.ReaderWriter: ,global,", + "System.Xml.XDocument: ,global,", + "System.Dynamic.Runtime: ,global,", + "System.Threading: ,global,", + "System.Text.Encoding.Extensions: ,global,", + "System.Xml.Linq: ,global,", + "System.Runtime.Serialization: ,global,", + "System.ServiceModel.Internals: ,global,", + "SMDiagnostics: ,global,", + "System.ComponentModel.Composition: ,global,", + "Microsoft.CodeAnalysis.CSharp: ,global", + "System.AppContext: ,global", + "System.Linq.Expressions: ,global", + "System.Threading.Tasks.Parallel: ,global"); + } + #endregion } } diff --git a/src/Scripting/Core/Hosting/CommandLine/CommandLineRunner.cs b/src/Scripting/Core/Hosting/CommandLine/CommandLineRunner.cs index eb4f8b9f9bc47..2c770f9833175 100644 --- a/src/Scripting/Core/Hosting/CommandLine/CommandLineRunner.cs +++ b/src/Scripting/Core/Hosting/CommandLine/CommandLineRunner.cs @@ -157,7 +157,7 @@ internal static MetadataReferenceResolver GetMetadataReferenceResolver(CommandLi (path, properties) => { loggerOpt?.AddRead(path); - return MetadataReference.CreateFromFile(path); + return MetadataReference.CreateFromFile(path, properties); }); } diff --git a/src/Scripting/Core/Hosting/Resolvers/RuntimeMetadataReferenceResolver.cs b/src/Scripting/Core/Hosting/Resolvers/RuntimeMetadataReferenceResolver.cs index 06526d27884d3..6596fe50b05c9 100644 --- a/src/Scripting/Core/Hosting/Resolvers/RuntimeMetadataReferenceResolver.cs +++ b/src/Scripting/Core/Hosting/Resolvers/RuntimeMetadataReferenceResolver.cs @@ -18,6 +18,9 @@ namespace Microsoft.CodeAnalysis.Scripting.Hosting /// internal sealed class RuntimeMetadataReferenceResolver : MetadataReferenceResolver, IEquatable { + // Ideally we'd use properties with no aliases, but currently that's not possible since empty aliases mean {global}. + private static readonly MetadataReferenceProperties ResolvedMissingAssemblyReferenceProperties = MetadataReferenceProperties.Assembly.WithAliases(ImmutableArray.Create("")); + public static readonly RuntimeMetadataReferenceResolver Default = new RuntimeMetadataReferenceResolver(ImmutableArray.Empty, baseDirectory: null); internal readonly RelativePathResolver PathResolver; @@ -56,7 +59,7 @@ public override PortableExecutableReference ResolveMissingAssembly(MetadataRefer var path = GacFileResolver.Resolve(referenceIdentity.GetDisplayName()); if (path != null) { - return CreateReference(path); + return CreateResolvedMissingReference(path); } } @@ -70,7 +73,7 @@ public override PortableExecutableReference ResolveMissingAssembly(MetadataRefer var fullPath = pathWithoutExtension + extension; if (File.Exists(fullPath)) { - return CreateReference(fullPath); + return CreateResolvedMissingReference(fullPath); } } } @@ -78,9 +81,9 @@ public override PortableExecutableReference ResolveMissingAssembly(MetadataRefer return null; } - private PortableExecutableReference CreateReference(string fullPath) + private PortableExecutableReference CreateResolvedMissingReference(string fullPath) { - return _fileReferenceProvider(fullPath, MetadataReferenceProperties.Assembly.WithRecursiveAliases(true)); + return _fileReferenceProvider(fullPath, ResolvedMissingAssemblyReferenceProperties); } public override ImmutableArray ResolveReference(string reference, string baseFilePath, MetadataReferenceProperties properties) @@ -115,6 +118,7 @@ public override ImmutableArray ResolveReference(str return ImmutableArray.Create(_fileReferenceProvider(path, properties)); } } + return ImmutableArray.Empty; } diff --git a/src/Scripting/Core/Script.cs b/src/Scripting/Core/Script.cs index a35c13eca9c27..5ac6aa640c496 100644 --- a/src/Scripting/Core/Script.cs +++ b/src/Scripting/Core/Script.cs @@ -171,6 +171,10 @@ public Compilation GetCompilation() internal abstract ImmutableArray CommonBuild(CancellationToken cancellationToken); internal abstract Func CommonGetExecutor(CancellationToken cancellationToken); + // Apply recursive alias to the host assembly reference, so that we hide its namespaces and global types behind it. + internal static readonly MetadataReferenceProperties HostAssemblyReferenceProperties = + MetadataReferenceProperties.Assembly.WithAliases(ImmutableArray.Create("")).WithRecursiveAliases(true); + /// /// Gets the references that need to be assigned to the compilation. /// This can be different than the list of references defined by the instance. @@ -197,7 +201,7 @@ internal ImmutableArray GetReferencesForCompilation( if (GlobalsType != null) { - var globalsTypeAssembly = MetadataReference.CreateFromAssemblyInternal(GlobalsType.GetTypeInfo().Assembly); + var globalsTypeAssembly = MetadataReference.CreateFromAssemblyInternal(GlobalsType.GetTypeInfo().Assembly, HostAssemblyReferenceProperties); references.Add(globalsTypeAssembly); } diff --git a/src/Scripting/Core/ScriptOptions.cs b/src/Scripting/Core/ScriptOptions.cs index a5a1058b51344..4211eb0dff3e1 100644 --- a/src/Scripting/Core/ScriptOptions.cs +++ b/src/Scripting/Core/ScriptOptions.cs @@ -84,6 +84,10 @@ private ScriptOptions(ScriptOptions other) { } + // a reference to an assembly should by default be equivalent to #r, which applies recursive global alias: + private static readonly MetadataReferenceProperties AssemblyReferenceProperties = + MetadataReferenceProperties.Assembly.WithRecursiveAliases(true); + /// /// Creates a new with the changed. /// @@ -91,7 +95,7 @@ public ScriptOptions WithFilePath(string filePath) => (FilePath == filePath) ? this : new ScriptOptions(this) { FilePath = filePath ?? "" }; private static MetadataReference CreateUnresolvedReference(string reference) => - new UnresolvedMetadataReference(reference, MetadataReferenceProperties.Assembly); + new UnresolvedMetadataReference(reference, AssemblyReferenceProperties); /// /// Creates a new with the references changed. @@ -132,7 +136,7 @@ public ScriptOptions AddReferences(params MetadataReference[] references) => /// /// is null or contains a null reference. public ScriptOptions WithReferences(IEnumerable references) => - WithReferences(SelectChecked(references, nameof(references), MetadataReference.CreateFromAssemblyInternal)); + WithReferences(SelectChecked(references, nameof(references), CreateReferenceFromAssembly)); /// /// Creates a new with the references changed. @@ -146,7 +150,12 @@ public ScriptOptions WithReferences(params Assembly[] references) => /// /// is null or contains a null reference. public ScriptOptions AddReferences(IEnumerable references) => - AddReferences(SelectChecked(references, nameof(references), MetadataReference.CreateFromAssemblyInternal)); + AddReferences(SelectChecked(references, nameof(references), CreateReferenceFromAssembly)); + + private static MetadataReference CreateReferenceFromAssembly(Assembly assembly) + { + return MetadataReference.CreateFromAssemblyInternal(assembly, AssemblyReferenceProperties); + } /// /// Creates a new with references added. diff --git a/src/Test/Utilities/Shared/Compilation/CompilationExtensions.cs b/src/Test/Utilities/Shared/Compilation/CompilationExtensions.cs index 5eb195d384edd..e5225cf080923 100644 --- a/src/Test/Utilities/Shared/Compilation/CompilationExtensions.cs +++ b/src/Test/Utilities/Shared/Compilation/CompilationExtensions.cs @@ -133,5 +133,13 @@ internal static CompilationDifference EmitDifference( updatedMethods.ToImmutableArray()); } } + + internal static void VerifyAssemblyAliases(this Compilation compilation, params string[] expectedAssembliesAndAliases) + { + var actual = compilation.GetBoundReferenceManager().GetReferencedAssemblyAliases(). + Select(t => $"{t.Item1.Identity.Name}{(t.Item2.IsEmpty ? "" : ": " + string.Join(",", t.Item2))}"); + + AssertEx.Equal(expectedAssembliesAndAliases, actual, itemInspector: s => '"' + s + '"'); + } } }