diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 5e0961a12ece12c4c030ddcfe1370c1d6202c572..bc6b91a5c0b553609abf4a500325eb0a8f2a533b 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -848,7 +848,7 @@ public override ImmutableArray DirectiveReferences } } - internal override IDictionary ReferenceDirectiveMap + internal override IDictionary, MetadataReference> ReferenceDirectiveMap { get { @@ -911,10 +911,11 @@ internal override IEnumerable ReferenceDirectives /// Returns a metadata reference that a given #r resolves to. /// /// #r directive. - /// Metadata reference the specified directive resolves to. + /// Metadata reference the specified directive resolves to, or null if the doesn't match any #r directive in the compilation. public MetadataReference GetDirectiveReference(ReferenceDirectiveTriviaSyntax directive) { - return ReferenceDirectiveMap[directive.File.ValueText]; + MetadataReference reference; + return ReferenceDirectiveMap.TryGetValue(ValueTuple.Create(directive.SyntaxTree.FilePath, directive.File.ValueText), out reference) ? reference : null; } /// diff --git a/src/Compilers/CSharp/Portable/Symbols/ReferenceManager.cs b/src/Compilers/CSharp/Portable/Symbols/ReferenceManager.cs index b751e5dd51054474cc4987b7ec238dad997dfc70..07ccbe3458e4126161779f5b4b4110f1ad8d6473 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ReferenceManager.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ReferenceManager.cs @@ -313,7 +313,7 @@ private bool CreateAndSetSourceAssemblyFullBind(CSharpCompilation compilation) try { - IDictionary boundReferenceDirectiveMap; + IDictionary, MetadataReference> boundReferenceDirectiveMap; ImmutableArray boundReferenceDirectives; ImmutableArray referencedAssemblies; ImmutableArray modules; // To make sure the modules are not collected ahead of time. diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs index b7d9e1ed05fbc32ce47d8aca30b010fe333cd1b9..d8c8f37c46a4ed52572f88d144cfb8b72266c242 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs @@ -13,6 +13,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Test.Utilities; @@ -326,6 +327,59 @@ public void ReferenceAPITest() Assert.Equal(0, compCollection.ExternalReferences.Length); } + [Fact] + public void ReferenceDirectiveTests() + { + var t1 = Parse(@" +#r ""a.dll"" +#r ""a.dll"" +", filename: "1.csx", options: TestOptions.Script); + + var rd1 = t1.GetRoot().GetDirectives().Cast().ToArray(); + Assert.Equal(2, rd1.Length); + + var t2 = Parse(@" +#r ""a.dll"" +#r ""b.dll"" +", options: TestOptions.Script); + + var rd2 = t2.GetRoot().GetDirectives().Cast().ToArray(); + Assert.Equal(2, rd2.Length); + + var t3 = Parse(@" +#r ""a.dll"" +", filename: "1.csx", options: TestOptions.Script); + + var rd3 = t3.GetRoot().GetDirectives().Cast().ToArray(); + Assert.Equal(1, rd3.Length); + + var t4 = Parse(@" +#r ""a.dll"" +", filename: "4.csx", options: TestOptions.Script); + + var rd4 = t4.GetRoot().GetDirectives().Cast().ToArray(); + Assert.Equal(1, rd4.Length); + + var c = CreateCompilationWithMscorlib45(new[] { t1, t2 }, options: TestOptions.ReleaseDll.WithMetadataReferenceResolver( + new TestMetadataReferenceResolver(files: new Dictionary() + { + { @"a.dll", TestReferences.NetFx.v4_0_30319.Microsoft_CSharp }, + { @"b.dll", TestReferences.NetFx.v4_0_30319.Microsoft_VisualBasic }, + }))); + + c.VerifyDiagnostics(); + + // same containing script file name and directive string + Assert.Same(TestReferences.NetFx.v4_0_30319.Microsoft_CSharp, c.GetDirectiveReference(rd1[0])); + Assert.Same(TestReferences.NetFx.v4_0_30319.Microsoft_CSharp, c.GetDirectiveReference(rd1[1])); + Assert.Same(TestReferences.NetFx.v4_0_30319.Microsoft_CSharp, c.GetDirectiveReference(rd2[0])); + Assert.Same(TestReferences.NetFx.v4_0_30319.Microsoft_VisualBasic, c.GetDirectiveReference(rd2[1])); + Assert.Same(TestReferences.NetFx.v4_0_30319.Microsoft_CSharp, c.GetDirectiveReference(rd3[0])); + + // different script name or directive string: + Assert.Null(c.GetDirectiveReference(rd4[0])); + } + [Fact, WorkItem(530131, "DevDiv")] public void MetadataReferenceWithInvalidAlias() { diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/ReferenceManagerTests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/ReferenceManagerTests.cs index 248fbfc052be9a7f60e56cd8ef09292170ca29ee..ec56178dbd8548f6da6aa0739d7e37fcced8f7e9 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/ReferenceManagerTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/ReferenceManagerTests.cs @@ -7,6 +7,7 @@ using System.IO; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; @@ -1345,6 +1346,40 @@ public void ResolvedReferencesCaching() var a2 = c2.SourceAssembly; } + [Fact] + public void ReferenceResolution_RelativePaths() + { + var t1 = Parse(@" +#r ""lib.dll"" +", filename: @"C:\A\a.csx", options: TestOptions.Script); + + var rd1 = (ReferenceDirectiveTriviaSyntax)t1.GetRoot().GetDirectives().Single(); + + var t2 = Parse(@" +#r ""lib.dll"" +", filename: @"C:\B\b.csx", options: TestOptions.Script); + + var rd2 = (ReferenceDirectiveTriviaSyntax)t2.GetRoot().GetDirectives().Single(); + + var c = CreateCompilationWithMscorlib45(new[] { t1, t2 }, options: TestOptions.ReleaseDll.WithMetadataReferenceResolver( + new TestMetadataReferenceResolver( + pathResolver: new VirtualizedRelativePathResolver(new[] + { + @"C:\A\lib.dll", + @"C:\B\lib.dll" + }), + files: new Dictionary() + { + { @"C:\A\lib.dll", TestReferences.NetFx.v4_0_30319.Microsoft_CSharp }, + { @"C:\B\lib.dll", TestReferences.NetFx.v4_0_30319.Microsoft_VisualBasic }, + }))); + + c.VerifyDiagnostics(); + + Assert.Same(TestReferences.NetFx.v4_0_30319.Microsoft_CSharp, c.GetDirectiveReference(rd1)); + Assert.Same(TestReferences.NetFx.v4_0_30319.Microsoft_VisualBasic, c.GetDirectiveReference(rd2)); + } + [Fact] public void CyclesInReferences() { diff --git a/src/Compilers/Core/Portable/Compilation/Compilation.cs b/src/Compilers/Core/Portable/Compilation/Compilation.cs index 00f582fe9ca9bb340a870ac0a5d880d17822b2a2..c0c6b6cb3586ab09e6a347494e14b879853e1d82 100644 --- a/src/Compilers/Core/Portable/Compilation/Compilation.cs +++ b/src/Compilers/Core/Portable/Compilation/Compilation.cs @@ -495,7 +495,7 @@ internal CommonReferenceManager GetBoundReferenceManager() /// /// Maps values of #r references to resolved metadata references. /// - internal abstract IDictionary ReferenceDirectiveMap { get; } + internal abstract IDictionary, MetadataReference> ReferenceDirectiveMap { get; } /// /// All metadata references -- references passed to the compilation diff --git a/src/Compilers/Core/Portable/ReferenceManager/CommonReferenceManager.Resolution.cs b/src/Compilers/Core/Portable/ReferenceManager/CommonReferenceManager.Resolution.cs index 868c781e86518274ca0deb53c33012f19a412c1a..60c80d6168bf44437347f108bdeac8b9f12f0085 100644 --- a/src/Compilers/Core/Portable/ReferenceManager/CommonReferenceManager.Resolution.cs +++ b/src/Compilers/Core/Portable/ReferenceManager/CommonReferenceManager.Resolution.cs @@ -192,7 +192,7 @@ public ReferencedAssemblyIdentity(AssemblyIdentity identity, MetadataReference r TCompilation compilation, [Out] Dictionary> assemblyReferencesBySimpleName, out ImmutableArray references, - out IDictionary boundReferenceDirectiveMap, + out IDictionary, MetadataReference> boundReferenceDirectiveMap, out ImmutableArray boundReferenceDirectives, out ImmutableArray assemblies, out ImmutableArray modules, @@ -744,7 +744,7 @@ private static void AddModule(PEModule module, int referenceIndex, ResolvedRefer TCompilation compilation, DiagnosticBag diagnostics, out ImmutableArray references, - out IDictionary boundReferenceDirectives, + out IDictionary, MetadataReference> boundReferenceDirectives, out ImmutableArray referenceDirectiveLocations) { boundReferenceDirectives = null; @@ -763,7 +763,7 @@ private static void AddModule(PEModule module, int referenceIndex, ResolvedRefer } // we already successfully bound #r with the same value: - if (boundReferenceDirectives != null && boundReferenceDirectives.ContainsKey(referenceDirective.File)) + if (boundReferenceDirectives != null && boundReferenceDirectives.ContainsKey(ValueTuple.Create(referenceDirective.Location.SourceTree.FilePath, referenceDirective.File))) { continue; } @@ -777,13 +777,13 @@ private static void AddModule(PEModule module, int referenceIndex, ResolvedRefer if (boundReferenceDirectives == null) { - boundReferenceDirectives = new Dictionary(); + boundReferenceDirectives = new Dictionary, MetadataReference>(); referenceDirectiveLocationsBuilder = ArrayBuilder.GetInstance(); } referencesBuilder.Add(boundReference); referenceDirectiveLocationsBuilder.Add(referenceDirective.Location); - boundReferenceDirectives.Add(referenceDirective.File, boundReference); + boundReferenceDirectives.Add(ValueTuple.Create(referenceDirective.Location.SourceTree.FilePath, referenceDirective.File), boundReference); } // add external reference at the end, so that they are processed first: @@ -792,7 +792,7 @@ private static void AddModule(PEModule module, int referenceIndex, ResolvedRefer if (boundReferenceDirectives == null) { // no directive references resolved successfully: - boundReferenceDirectives = SpecializedCollections.EmptyDictionary(); + boundReferenceDirectives = SpecializedCollections.EmptyDictionary, MetadataReference>(); } references = referencesBuilder.ToImmutable(); diff --git a/src/Compilers/Core/Portable/ReferenceManager/CommonReferenceManager.State.cs b/src/Compilers/Core/Portable/ReferenceManager/CommonReferenceManager.State.cs index 487cfb5feb43a73fd84ab1a76584d96959e0a555..31778121b11efa59826da8ed19d1cde21160e701 100644 --- a/src/Compilers/Core/Portable/ReferenceManager/CommonReferenceManager.State.cs +++ b/src/Compilers/Core/Portable/ReferenceManager/CommonReferenceManager.State.cs @@ -94,10 +94,10 @@ internal partial class CommonReferenceManager : C private Dictionary _lazyReferencedModuleIndexMap; /// - /// Maps reference string used in #r directive to a resolved metadata reference. - /// If multiple #r's use the same value as a reference the resolved metadata reference is the same as well. + /// Maps (containing syntax tree file name, reference string) of #r directive to a resolved metadata reference. + /// If multiple #r's in the same tree use the same value as a reference the resolved metadata reference is the same as well. /// - private IDictionary _lazyReferenceDirectiveMap; + private IDictionary, MetadataReference> _lazyReferenceDirectiveMap; /// /// Array of unique bound #r references. @@ -210,7 +210,7 @@ internal bool HasCircularReference } } - internal IDictionary ReferenceDirectiveMap + internal IDictionary, MetadataReference> ReferenceDirectiveMap { get { @@ -345,7 +345,7 @@ internal bool IsBound internal void InitializeNoLock( Dictionary referencedAssembliesMap, Dictionary referencedModulesMap, - IDictionary boundReferenceDirectiveMap, + IDictionary, MetadataReference> boundReferenceDirectiveMap, ImmutableArray boundReferenceDirectives, bool containsCircularReferences, ImmutableArray diagnostics, diff --git a/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb index e337fec81b8bc27e391cdeb0eeac7ac6250c9c5e..f62e652264a91123c0a6f05f6168d059511bbdc5 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb @@ -1184,7 +1184,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property - Friend Overrides ReadOnly Property ReferenceDirectiveMap As IDictionary(Of String, MetadataReference) + Friend Overrides ReadOnly Property ReferenceDirectiveMap As IDictionary(Of ValueTuple(Of String, String), MetadataReference) Get Return GetBoundReferenceManager().ReferenceDirectiveMap End Get diff --git a/src/Compilers/VisualBasic/Portable/Symbols/ReferenceManager.vb b/src/Compilers/VisualBasic/Portable/Symbols/ReferenceManager.vb index 7654b4580a1c7a0c06f22edaad8b3d1d27902215..2902e89b4e6c69e356497933a8eaf0a9871bbc20 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/ReferenceManager.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/ReferenceManager.vb @@ -262,7 +262,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim assemblyReferencesBySimpleName = PooledDictionary(Of String, List(Of ReferencedAssemblyIdentity)).GetInstance() Try - Dim boundReferenceDirectiveMap As IDictionary(Of String, MetadataReference) = Nothing + Dim boundReferenceDirectiveMap As IDictionary(Of ValueTuple(Of String, String), MetadataReference) = Nothing Dim boundReferenceDirectives As ImmutableArray(Of MetadataReference) = Nothing Dim referencedAssemblies As ImmutableArray(Of AssemblyData) = Nothing Dim modules As ImmutableArray(Of PEModule) = Nothing ' To make sure the modules are not collected ahead of time.