diff --git a/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs b/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs index c389b2611b0d4..f0d129d8a4fa3 100644 --- a/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs +++ b/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs @@ -1482,6 +1482,8 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar new CSharpRequiredLanguageVersion(MessageID.IDS_FeatureNullableReferenceTypes.RequiredVersion())), Location.None)); } + pathMap = SortPathMap(pathMap); + return new CSharpCommandLineArguments { IsScriptRunner = IsScriptCommandLineParser, diff --git a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs index a5ab4f7b52dc6..73989b6b74c72 100644 --- a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs +++ b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs @@ -10740,6 +10740,12 @@ public void PathMapParser() parsedArgs.Errors.Verify(); Assert.Equal(KeyValuePairUtil.Create("a =,b" + s, "1,= 2" + s), parsedArgs.PathMap[0]); Assert.Equal(KeyValuePairUtil.Create("x =,y" + s, "3 4" + s), parsedArgs.PathMap[1]); + + parsedArgs = DefaultParse(new[] { @"/pathmap:C:\temp\=/_1/,C:\temp\a\=/_2/,C:\temp\a\b\=/_3/", "a.cs", @"a\b.cs", @"a\b\c.cs" }, WorkingDirectory); + parsedArgs.Errors.Verify(); + Assert.Equal(KeyValuePairUtil.Create(@"C:\temp\a\b\", "/_3/"), parsedArgs.PathMap[0]); + Assert.Equal(KeyValuePairUtil.Create(@"C:\temp\a\", "/_2/"), parsedArgs.PathMap[1]); + Assert.Equal(KeyValuePairUtil.Create(@"C:\temp\", "/_1/"), parsedArgs.PathMap[2]); } [Theory] diff --git a/src/Compilers/Core/Portable/CommandLine/CommandLineParser.cs b/src/Compilers/Core/Portable/CommandLine/CommandLineParser.cs index 0128d2b51fa26..e3bf9b818d0b0 100644 --- a/src/Compilers/Core/Portable/CommandLine/CommandLineParser.cs +++ b/src/Compilers/Core/Portable/CommandLine/CommandLineParser.cs @@ -1195,5 +1195,13 @@ internal static ImmutableDictionary ParseFeatures(List f CompilerOptionParseUtilities.ParseFeatures(builder, features); return builder.ToImmutable(); } + + /// + /// Sort so that more specific keys precede less specific. + /// When mapping a path we find the first key in the array that is a prefix of the path. + /// If multiple keys are prefixes of the path we want to use the longest (more specific) one for the mapping. + /// + internal static ImmutableArray> SortPathMap(ImmutableArray> pathMap) + => pathMap.Sort((x, y) => -x.Key.Length.CompareTo(y.Key.Length)); } } diff --git a/src/Compilers/Core/Portable/SourceFileResolver.cs b/src/Compilers/Core/Portable/SourceFileResolver.cs index c9d8aad024941..1d60efada721b 100644 --- a/src/Compilers/Core/Portable/SourceFileResolver.cs +++ b/src/Compilers/Core/Portable/SourceFileResolver.cs @@ -60,15 +60,13 @@ public SourceFileResolver( { var pathMapBuilder = ArrayBuilder>.GetInstance(pathMap.Length); - foreach (var kv in pathMap) + foreach (var (key, value) in pathMap) { - var key = kv.Key; if (key == null || key.Length == 0) { throw new ArgumentException(CodeAnalysisResources.EmptyKeyInPathMap, nameof(pathMap)); } - var value = kv.Value; if (value == null) { throw new ArgumentException(CodeAnalysisResources.NullValueInPathMap, nameof(pathMap)); diff --git a/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCommandLineParser.vb b/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCommandLineParser.vb index 3ba9003ea4919..6be41e8f1dc1a 100644 --- a/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCommandLineParser.vb +++ b/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCommandLineParser.vb @@ -1440,6 +1440,8 @@ lVbRuntimePlus: ' If the script is passed without the `\i` option simply execute the script (`vbi script.vbx`). interactiveMode = interactiveMode Or (IsScriptCommandLineParser AndAlso sourceFiles.Count = 0) + pathMap = SortPathMap(pathMap) + Return New VisualBasicCommandLineArguments With { .IsScriptRunner = IsScriptCommandLineParser, diff --git a/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb b/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb index 890fba65ecc91..ad35e10cfbadf 100644 --- a/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb +++ b/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb @@ -3483,6 +3483,12 @@ print Goodbye, World" parsedArgs.Errors.Verify() Assert.Equal(KeyValuePairUtil.Create("a =,b" & s, "1,= 2" & s), parsedArgs.PathMap(0)) Assert.Equal(KeyValuePairUtil.Create("x =,y" & s, "3 4" & s), parsedArgs.PathMap(1)) + + parsedArgs = DefaultParse({"/pathmap:C:\temp\=/_1/,C:\temp\a\=/_2/,C:\temp\a\b\=/_3/", "a.cs", "a\b.cs", "a\b\c.cs"}, _baseDirectory) + parsedArgs.Errors.Verify() + Assert.Equal(KeyValuePairUtil.Create("C:\temp\a\b\", "/_3/"), parsedArgs.PathMap(0)) + Assert.Equal(KeyValuePairUtil.Create("C:\temp\a\", "/_2/"), parsedArgs.PathMap(1)) + Assert.Equal(KeyValuePairUtil.Create("C:\temp\", "/_1/"), parsedArgs.PathMap(2)) End Sub ' PathMapKeepsCrossPlatformRoot and PathMapInconsistentSlashes should be in an