diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs index 4ab3ceaa48867..33c4e8adad8b9 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs @@ -5229,7 +5229,7 @@ internal InterceptableLocation GetInterceptableLocationInternal(SyntaxNode nameS var lineNumberOneIndexed = lineSpan.Line + 1; var characterNumberOneIndexed = lineSpan.Character + 1; - return new InterceptableLocation1(checksum, path, nameSyntax.Position, lineNumberOneIndexed, characterNumberOneIndexed); + return new InterceptableLocation1(checksum, path, Compilation.Options.SourceReferenceResolver, nameSyntax.Position, lineNumberOneIndexed, characterNumberOneIndexed); } #nullable disable diff --git a/src/Compilers/CSharp/Portable/Utilities/InterceptableLocation.cs b/src/Compilers/CSharp/Portable/Utilities/InterceptableLocation.cs index e262cfb34d5bd..85c76ab47e0e4 100644 --- a/src/Compilers/CSharp/Portable/Utilities/InterceptableLocation.cs +++ b/src/Compilers/CSharp/Portable/Utilities/InterceptableLocation.cs @@ -53,12 +53,13 @@ internal sealed class InterceptableLocation1 : InterceptableLocation private readonly ImmutableArray _checksum; private readonly string _path; + private readonly SourceReferenceResolver? _resolver; private readonly int _position; private readonly int _lineNumberOneIndexed; private readonly int _characterNumberOneIndexed; private string? _lazyData; - internal InterceptableLocation1(ImmutableArray checksum, string path, int position, int lineNumberOneIndexed, int characterNumberOneIndexed) + internal InterceptableLocation1(ImmutableArray checksum, string path, SourceReferenceResolver? resolver, int position, int lineNumberOneIndexed, int characterNumberOneIndexed) { Debug.Assert(checksum.Length == ContentHashLength); Debug.Assert(path is not null); @@ -68,6 +69,7 @@ internal InterceptableLocation1(ImmutableArray checksum, string path, int _checksum = checksum; _path = path; + _resolver = resolver; _position = position; _lineNumberOneIndexed = lineNumberOneIndexed; _characterNumberOneIndexed = characterNumberOneIndexed; @@ -75,8 +77,10 @@ internal InterceptableLocation1(ImmutableArray checksum, string path, int public override string GetDisplayLocation() { + var mappedPath = _resolver?.NormalizePath(_path, baseFilePath: null) ?? _path; // e.g. `C:\project\src\Program.cs(12,34)` - return $"{_path}({_lineNumberOneIndexed},{_characterNumberOneIndexed})"; + // or, with a typical pathmap setup, `/_/src/Program.cs(12,34)` + return $"{mappedPath}({_lineNumberOneIndexed},{_characterNumberOneIndexed})"; } public override string ToString() => GetDisplayLocation(); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InterceptorsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InterceptorsTests.cs index d3f1fc22cf5da..5789d0bf7059d 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InterceptorsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InterceptorsTests.cs @@ -5216,6 +5216,46 @@ static class MyDeconstructableExt ); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76126")] + public void DisplayPathMapping_01() + { + var pathPrefix = PlatformInformation.IsWindows ? """C:\My\Machine\Specific\Path\""" : "/My/Machine/Specific/Path/"; + var path = pathPrefix + "Program.cs"; + var resolver = new SourceFileResolver([], null, [new KeyValuePair(pathPrefix, "/_/")]); + var options = TestOptions.DebugExe.WithSourceReferenceResolver(resolver); + + var source = (""" + C c = new C(); + c.M(); + """, path); + var comp = CreateCompilation(source, options: options); + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var node = tree.GetRoot().DescendantNodes().OfType().Single(); + var location = model.GetInterceptableLocation(node)!; + Assert.Equal("/_/Program.cs(2,3)", location.GetDisplayLocation()); + + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; + + class C + { + public void M() => throw null!; + + [InterceptsLocation({{GetAttributeArgs(location)}})] + public void Interceptor() => Console.Write(1); + } + """; + + var verifier = CompileAndVerify( + [source, interceptors, s_attributesSource], + parseOptions: RegularWithInterceptors, + options: options, + expectedOutput: "1"); + verifier.VerifyDiagnostics(); + } + [Fact] public void PathMapping_01() {