RLovelett / langserver-swift

A Swift implementation of the open Language Server Protocol.
Apache License 2.0
177 stars 16 forks source link

Cross-module definition doesn't work #52

Open chrismwendt opened 6 years ago

chrismwendt commented 6 years ago

2018-05-31 13 15 09

This happens because the framework path for the project is not getting passed to the swift compiler.

$ swift --help
...
  -F <value>              Add directory to framework search path
...

With -F, cursorinfo across modules works (I'm on bebf0d1):

cat <<EOF | sourcekitd-repl
{
  key.request: source.request.cursorinfo,
  key.compilerargs: [
    "-sdk",
    "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk",
    "-F",
    "/Users/chrismwendt/Library/Developer/Xcode/DerivedData/langserver-swift-decoewqzatmxuugoqscoirgsoekn/Build/Products/Debug",
    "/Users/chrismwendt/langserver-swift/Sources/LanguageServer/main.swift",
  ],
  key.offset: 368,
  key.sourcefile: "/Users/chrismwendt/langserver-swift/Sources/LanguageServer/main.swift",
}
EOF

And returns:

{
  key.kind: source.lang.swift.ref.class,
  key.name: "RequestBuffer",
  key.usr: "s:12BaseProtocol13RequestBufferC",
  key.typename: "RequestBuffer.Type",
  key.annotated_decl: "<Declaration>class RequestBuffer</Declaration>",
  key.fully_annotated_decl: "<decl.class><syntaxtype.keyword>class</syntaxtype.keyword> <decl.name>RequestBuffer</decl.name></decl.class>",
  key.typeusr: "_T012BaseProtocol13RequestBufferCmD",
  key.modulename: "BaseProtocol"
}

The correct path can be obtained by running this build command (similar to the one listed in the README:

$ xcodebuild -project langserver-swift.xcodeproj -scheme langserver-swift -showBuildSettings | grep "TARGET_BUILD_DIR"
   TARGET_BUILD_DIR = /Users/chrismwendt/Library/Developer/Xcode/DerivedData/langserver-swift-decoewqzatmxuugoqscoirgsoekn/Build/Products/Debug

The -scheme langserver-swift can be obtained with swift package dump-package | jq -r .name, but it's probably not safe to assume that there is a scheme with the same name as the package.

I'm thinking about running those commands and passing it to the compiler at https://github.com/chrismwendt/langserver-swift/blob/bebf0d10c51c8c0fa71d557b4fcf90fb92e64615/Sources/LanguageServerProtocol/Types/Server.swift#L179

@RLovelett Does this approach make sense?

chrismwendt commented 6 years ago

Hmm, the USR s:12BaseProtocol13RequestBufferC from main.swift doesn't match anything:

$ sourcekitten index --file /Users/chrismwendt/langserver-swift/Sources/BaseProtocol/Types/RequestBuffer.swift --compilerargs -- /Users/chrismwendt/langserver-swift/Sources/BaseProtocol/Types/RequestBuffer.swift
...
"key.usr" : "s:13RequestBufferAAC"
...

It looks like all the USRs in RequestBuffer.swift begin with s:13 instead of s:12. Are they not supposed to match? How might I stitch these together?

RLovelett commented 6 years ago

The correct path can be obtained by running this build command (similar to the one listed in the README

Those paths are meant to be generated by SwiftPM. That is the whole point of including SwiftPM as a dependency. That it will know how to properly build those. So the fix for this should come from SwiftPM. Or that is my off-the-cuff gut response.

I would first look through the .build directory and see if it contains the path you are looking for first. If it's in there then we can work backwards on how to extract that info from SwiftPM. If it is not, then we'll have to figure out how to coerce SwiftPM to build that info for us.

It looks like all the USRs in RequestBuffer.swift begin with s:13 instead of s:12. Are they not supposed to match? How might I stitch these together?

So when you compile main.swift are you using the same module that you are sending to the index?

Because they should match. If they don't match I don't know how you would be able to reliably match them. The only thing that feels like might be true is that if you are not sending the exact same compiler args for then it might not end up with the same USR because it sees it as a different module and tries to de-conflict it with a new USR.

Another way that I've thought this might have to work is that you make use of Module Interface Generation. Basically find the module that defines the type in main.swift. Then generate the interface which will contain the USR local to the module. Then use find_usr to get the definition.

chrismwendt commented 6 years ago

So when you compile main.swift are you using the same module that you are sending to the index?

Ah-hah! I just had to pass ALL of the Swift files under Sources/ in the key.compilerargs array.

Now the USRs are the same and -F is unnecessary! 🎉 🎊

Do you have an example of source.request.editor.open.interface and find_usr working? I can't figure out what to specify for key.modulename - I keep getting the error "Could not load module".