diff --git a/src/OmniSharp.Roslyn.CSharp/Helpers/LocationExtensions.cs b/src/OmniSharp.Roslyn.CSharp/Helpers/LocationExtensions.cs index 8f380fddb4..5ab5782ba5 100644 --- a/src/OmniSharp.Roslyn.CSharp/Helpers/LocationExtensions.cs +++ b/src/OmniSharp.Roslyn.CSharp/Helpers/LocationExtensions.cs @@ -24,10 +24,15 @@ public static QuickFix GetQuickFix(this Location location, OmniSharpWorkspace wo var sourceText = GetSourceText(location, documents, lineSpan.HasMappedPath); var text = GetLineText(location, sourceText, lineSpan.StartLinePosition.Line); + var fileName = Path.IsPathRooted(lineSpan.Path) + ? lineSpan.Path + // when a #line directive maps into a separate file using a relative path, get the full path relative to the folder containing the source tree + : Path.GetFullPath(Path.Combine(Path.GetDirectoryName(location.SourceTree.FilePath), lineSpan.Path)); + return new QuickFix { Text = text.Trim(), - FileName = lineSpan.Path, + FileName = fileName, Line = lineSpan.StartLinePosition.Line, Column = lineSpan.HasMappedPath ? 0 : lineSpan.StartLinePosition.Character, // when a #line directive maps into a separate file, assume columns (0,0) EndLine = lineSpan.EndLinePosition.Line, diff --git a/tests/OmniSharp.Lsp.Tests/ReferencesHandlerFacts.cs b/tests/OmniSharp.Lsp.Tests/ReferencesHandlerFacts.cs index 1223d69164..7c81a30df4 100644 --- a/tests/OmniSharp.Lsp.Tests/ReferencesHandlerFacts.cs +++ b/tests/OmniSharp.Lsp.Tests/ReferencesHandlerFacts.cs @@ -215,8 +215,8 @@ public FooConsumer() var regularResult = usages.ElementAt(0); var mappedResult = usages.ElementAt(1); - Assert.Equal("a.cs", regularResult.Uri); - Assert.Equal("b.cs", mappedResult.Uri); + Assert.EndsWith("a.cs", regularResult.Uri.Path); + Assert.EndsWith("b.cs", mappedResult.Uri.Path); Assert.Equal(3, regularResult.Range.Start.Line); Assert.Equal(mappingLine - 1, mappedResult.Range.Start.Line); @@ -405,7 +405,7 @@ public Vector2Consumer() private Task FindUsagesAsync(string code, bool excludeDefinition = false) { - return FindUsagesAsync(new[] {new TestFile("dummy.cs", code)}, excludeDefinition); + return FindUsagesAsync(new[] { new TestFile("dummy.cs", code) }, excludeDefinition); } private async Task FindUsagesAsync(TestFile[] testFiles, bool excludeDefinition = false) diff --git a/tests/OmniSharp.Roslyn.CSharp.Tests/FindImplementationFacts.cs b/tests/OmniSharp.Roslyn.CSharp.Tests/FindImplementationFacts.cs index 977d862a84..03ad2dfeb9 100644 --- a/tests/OmniSharp.Roslyn.CSharp.Tests/FindImplementationFacts.cs +++ b/tests/OmniSharp.Roslyn.CSharp.Tests/FindImplementationFacts.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis; @@ -212,7 +213,7 @@ private async Task> SymbolsFromQuickFixesAsync(OmniSharpWor var symbols = new List(); foreach (var quickfix in quickFixes) { - var document = workspace.GetDocument(quickfix.FileName); + var document = workspace.GetDocument(Path.GetFileName(quickfix.FileName)); var sourceText = await document.GetTextAsync(); var position = sourceText.Lines.GetPosition(new LinePosition(quickfix.Line, quickfix.Column)); var semanticModel = await document.GetSemanticModelAsync(); diff --git a/tests/OmniSharp.Roslyn.CSharp.Tests/FindReferencesFacts.cs b/tests/OmniSharp.Roslyn.CSharp.Tests/FindReferencesFacts.cs index 583680a418..22087b4d83 100644 --- a/tests/OmniSharp.Roslyn.CSharp.Tests/FindReferencesFacts.cs +++ b/tests/OmniSharp.Roslyn.CSharp.Tests/FindReferencesFacts.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; using OmniSharp.Models; @@ -132,7 +133,7 @@ public class FooConsumer { public FooConsumer() { -#line " + mappingLine+ @" +#line " + mappingLine + @" new Foo().bar(); #line default } @@ -145,14 +146,14 @@ public FooConsumer() var regularResult = quickFixes.ElementAt(0); var mappedResult = quickFixes.ElementAt(1); - Assert.Equal("dummy.cs", regularResult.FileName); - Assert.Equal("dummy.cs", mappedResult.FileName); + Assert.EndsWith("dummy.cs", regularResult.FileName); + Assert.EndsWith("dummy.cs", mappedResult.FileName); Assert.Equal("public void bar() { }", regularResult.Text); Assert.Equal(expectedMappingText, mappedResult.Text); Assert.Equal(3, regularResult.Line); - Assert.Equal(mappingLine-1, mappedResult.Line); + Assert.Equal(mappingLine - 1, mappedResult.Line); // regular result has regular postition Assert.Equal(32, regularResult.Column); @@ -186,7 +187,7 @@ public FooConsumer() #line default } }"), - + }; if (mappedFileExistsInWorkspace) @@ -201,11 +202,11 @@ public FooConsumer() var regularResult = usages.QuickFixes.ElementAt(0); var mappedResult = usages.QuickFixes.ElementAt(1); - Assert.Equal("a.cs", regularResult.FileName); - Assert.Equal("b.cs", mappedResult.FileName); + Assert.EndsWith("a.cs", regularResult.FileName); + Assert.EndsWith("b.cs", mappedResult.FileName); Assert.Equal(3, regularResult.Line); - Assert.Equal(mappingLine-1, mappedResult.Line); + Assert.Equal(mappingLine - 1, mappedResult.Line); Assert.Equal("public void bar() { }", regularResult.Text); Assert.Equal(expectedMappingText, mappedResult.Text); @@ -251,8 +252,8 @@ public FooConsumer() var regularResult = usages.QuickFixes.ElementAt(0); var mappedResult = usages.QuickFixes.ElementAt(1); - Assert.Equal("a.cs", regularResult.FileName); - Assert.Equal("a.cs", mappedResult.FileName); + Assert.EndsWith("a.cs", regularResult.FileName); + Assert.EndsWith("a.cs", mappedResult.FileName); Assert.Equal(3, regularResult.Line); Assert.Equal(11, mappedResult.Line); @@ -407,14 +408,42 @@ public Foo Clone() { var usages = await FindUsagesAsync(testFiles, onlyThisFile: false); Assert.Equal(3, usages.QuickFixes.Count()); - Assert.Equal("a.cs", usages.QuickFixes.ElementAt(0).FileName); - Assert.Equal("a.cs", usages.QuickFixes.ElementAt(1).FileName); - Assert.Equal("b.cs", usages.QuickFixes.ElementAt(2).FileName); + Assert.EndsWith("a.cs", usages.QuickFixes.ElementAt(0).FileName); + Assert.EndsWith("a.cs", usages.QuickFixes.ElementAt(1).FileName); + Assert.EndsWith("b.cs", usages.QuickFixes.ElementAt(2).FileName); usages = await FindUsagesAsync(testFiles, onlyThisFile: true); Assert.Equal(2, usages.QuickFixes.Count()); - Assert.Equal("a.cs", usages.QuickFixes.ElementAt(0).FileName); - Assert.Equal("a.cs", usages.QuickFixes.ElementAt(1).FileName); + Assert.EndsWith("a.cs", usages.QuickFixes.ElementAt(0).FileName); + Assert.EndsWith("a.cs", usages.QuickFixes.ElementAt(1).FileName); + } + + [Fact] + public async Task MappedLocationFileNameProperlyRooted() + { + var relativeFile = ".\\pages\\test.xaml"; + + var testFiles = new[] + { + new TestFile("a.cs", + @"public class Bar : F$$oo {}"), + new TestFile("b.cs", $@" + #line 23 ""{relativeFile}"" + public class Foo {{ }} + #line default + #line hidden") + }; + + var usages = await FindUsagesAsync(testFiles, onlyThisFile: false); + + Assert.DoesNotContain(usages.QuickFixes, location => location.FileName.EndsWith("b.cs")); + Assert.DoesNotContain(usages.QuickFixes, location => location.FileName.Equals(relativeFile)); + + var project = SharedOmniSharpTestHost.Workspace.CurrentSolution.Projects.Single(); + var projectFolder = Path.GetDirectoryName(project.FilePath); + var mappedFilePath = Path.GetFullPath(Path.Combine(projectFolder, relativeFile)); + + Assert.Single(usages.QuickFixes, location => location.FileName.Equals(mappedFilePath)); } [Fact] @@ -434,7 +463,7 @@ public Foo Clone() { var usages = await FindUsagesAsync(testFiles, onlyThisFile: true); Assert.Single(usages.QuickFixes); - Assert.Equal("a.cs", usages.QuickFixes.ElementAt(0).FileName); + Assert.EndsWith("a.cs", usages.QuickFixes.ElementAt(0).FileName); } [Theory] @@ -449,13 +478,13 @@ public class Foo {{ }} }}"; - - var exception = await Record.ExceptionAsync(async () => + + var exception = await Record.ExceptionAsync(async () => { var usages = await FindUsagesAsync(code); Assert.NotNull(usages); }); - + Assert.Null(exception); }