omnisharp-roslyn icon indicating copy to clipboard operation
omnisharp-roslyn copied to clipboard

goto definition tries to open an ominous /$metadata/Project/... path that doesn't exist

Open ArneDoering opened this issue 7 months ago • 9 comments

When I call goto definition on a type that is from one of the dependencies, I get the following question asked:

/$metadata$/Project/GetStartedApp/Assembly/Avalonia/Base/Symbol/Avalonia/Interactivity/RoutedEventArgs.cs is read-only on disk.  Make buffer read-only, too? (y or n) 

There is no folder called $metadata$ in the root directory. Trying to open this is futile.

ArneDoering avatar May 12 '25 08:05 ArneDoering

@ArneDoering How are you running O#? These paths are handled in a special way by the C# extension for VS Code (see source).

JoeRobich avatar May 12 '25 22:05 JoeRobich

I am using eglot, the generic lsp integration in emacs.

ArneDoering avatar May 13 '25 12:05 ArneDoering

When I call goto definition on a type that is from one of the dependencies, I get the following question asked:

/$metadata$/Project/GetStartedApp/Assembly/Avalonia/Base/Symbol/Avalonia/Interactivity/RoutedEventArgs.cs is read-only on disk.  Make buffer read-only, too? (y or n) 

There is no folder called $metadata$ in the root directory. Trying to open this is futile.

I created this root path $metadata$ and gave permissions to write in this path, but the eglot could not resolve to get the content file =/. Just creates a new empty file:

Image

AugustoDeveloper avatar Jul 13 '25 04:07 AugustoDeveloper

I wonder why such a core functionality of a LSP is left intentionally in a broken state.

@AugustoDeveloper thanks for verifying that this isn't just an emacs issue. It seem like you use vim?

ArneDoering avatar Jul 14 '25 08:07 ArneDoering

I wonder why such a core functionality of a LSP is left intentionally in a broken state.

@AugustoDeveloper thanks for verifying that this isn't just an emacs issue. It seem like you use vim?

We accept pull requests if you are interested in contributing a fix.

JoeRobich avatar Jul 14 '25 21:07 JoeRobich

@JoeRobich is anything actually broken here though?

As you said previously, /$metadata$/... paths are handled by clients.

So when attempting to navigate to definitions of code that doesn't actually exist in the codebase, e.g. reference assemblies, O# can return disassembled code. That code does not have a location in the filesystem. The vscode extension and omnisharp-vim create a buffer to display the disassembly code but it should not be written to disk.

nickspoons avatar Jul 14 '25 21:07 nickspoons

@JoeRobich is anything actually broken here though?

@nickspoons No. I should be more careful with how I respond.

I wonder why such a core functionality of a LSP is left intentionally in a broken stat

@ArneDoering Basically O# returns a metadata path, as these files do not exist on disk, and provides service calls for requesting the text for metadata files. It is up to each platform to implement the necessary code to request the text when navigating to metadata paths. An example of this is in the C# extension for VS Code (see source).

JoeRobich avatar Jul 16 '25 03:07 JoeRobich

I am sorry. I did not find the part of the LSP specification, that said that paths starting with /$metadata$ have to be treated specially by the client. To my knowledge the LSP server is resposible to hand over paths, that are actually valid.

As far as I know LSP has been developed by Microsoft, so that editors can integrate LSP integration once, and don't have to implement support for every language under the sun. This promise breaks as soon as a language thinks it is special, and may have special cases that need to be implemented by the clients in a special way.

And don't tell me, the LSP server couldn't just create and populate valid metadata folder on its own, and then return valid paths to it.

PS: Thanks for providing the link to the C# extention for VS Code.

ArneDoering avatar Jul 16 '25 06:07 ArneDoering

This promise breaks as soon as a language thinks it is special, and may have special cases that need to be implemented by the clients in a special way.

@ArneDoering O# predates LSP so it definitely developed its own way of doing things (O# Protocol). Where functionality overlaps it tries to map O# Protocol messages to provide LSP support. All this means that LSP support in O# is incomplete.

the LSP server could just create and populate valid metadata folder on its own

I could imagine some users would want to opt-in to this behavior. If you were interested in implementing this in O#, I would recommend first writing up a feature enhancement proposal so that we can work through the details.

JoeRobich avatar Jul 16 '25 06:07 JoeRobich