dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.2k stars 1.57k forks source link

Auto import (or quickfix?) for Extensions #38894

Closed shinayser closed 2 years ago

shinayser commented 5 years ago

I am opening this issue as @scheglov asked for at https://github.com/dart-lang/sdk/issues/25820#issuecomment-541972606

I am having problem with auto completing the new Extension Functions from dart 2.6.0. I have added a new file called "time.dart" with some extensions, like this:

image

My main file just can't auto complete it. If I try to quickfix the error I get the following:

image

As soon as I move the extensions to the same file as main, everything works:

image

If I add the import manually, it also works:

image

My Dart for Intellij plugin version is 192.6817.14

alexander-shustanov commented 3 years ago

Without this feature, the extensions are completely useless! Do you have any plans to implement it?

selcukguvel commented 2 years ago

As a workaround, we decided to put all extensions into a file and import it using a simple IntelliJ-based plugin we implemented. Basically, these are the steps:

esDotDev commented 2 years ago

You can also just start typing a class you know is in the extensions file, and then choose it from the list of suggested imports. I do this constantly with Provider for example.

Afur commented 2 years ago

image

That's my temporary solution for that issue. The only think that I need to do is just start typing Ext... and IntelliSense provides this stub class which holds reference to every extension file in my project.

MatrixDev commented 2 years ago

@Afur and how much refactoring will you need to do in order to change your code after code assist will start working as intended?

0ttik commented 2 years ago

@Afur and how much refactoring will you need to do in order to change your code after code assist will start working as intended?

Don't see any problem with this. Basically, it's even usefull to have all extensions collected together. Also, you can refactor incrementally. Anyway, after code completion is working as intended, you can just remove this abstract class and go through all errors in project and add correct imports using IDEA hints with hotkeys if you want to refactor all at once, but I don't see real necessity in it.

ipowell commented 2 years ago

This is working for me now. I just upgraded Flutter to 2.10.0, the current stable channel. Dart version is 2.16.0.

bwilkerson commented 2 years ago

Excellent! Glad to hear it, and thanks for letting us know.

esDotDev commented 2 years ago

I have seen this working in beta for a while, but it seems only when I write the entire method name perfectly, then I can import. Is that what everyone else is seeing?

extension Foo on String {
  blah() => print(this);
}

image

Works with blah though.

m-skolnick commented 2 years ago

@esDotDev That is what I'm seeing as well. It's not very helpful.

When I saw the comment from @ipowell I was hoping that the extension would show in the autocomplete options. For example, in the below pic I would expect that myExtensionMethod would show in the options window even though the file with the extension is not imported.

Screen Shot 2022-02-04 at 5 01 58 PM

bwilkerson commented 2 years ago

Yes, the piece to get extension members from extensions in libraries that are not yet imported still isn't complete.

shinayser commented 2 years ago

Hey @bwilkerson this sounds a very important feature to add to the language, but considering the time I've opened the issue and it isn't fixed, I can assume that definitely is not an easy task.

Perhaps you can explain to us the difficulty of that issue? Maybe we can try to find a workaround and open an PR :)

bwilkerson commented 2 years ago

It's definitely an important feature. The delay is primarily a result of (a) the current architecture of the code completion support and (b) limited resources.

When we first decided to start suggesting completions from libraries that weren't imported (about three years ago), we first tried the simple tactic of just adding the suggestions to the completion results. Unfortunately, this had some performance issues due to (a) having to process all of the elements from these un-imported libraries in order to create suggestions, and (b) the large amount of data that was being sent from the the server to the client (the IDE). These issues led to an unusable code completion experience.

So we designed a new protocol. The new protocol, which we're still using today, allowed the server to send all of the suggestions from un-imported libraries during the initial analysis and to keep it updated if the user changed which packages were available to a given package. That protocol was designed before extensions were introduced into the language and isn't flexible enough to support extension members.

We have considered changes to the protocol, and that's still an option that we're discussing, but we're currently looking at other approaches.

We changed our use of the protocol slightly, which is what allows us to suggest extension members if the package defining the extension is already imported. Initially we decided to use the same ahead-of-time computation of suggestions for imported libraries as for un-imported libraries. Now we're back to computing and sending suggestions from imported libraries at the time that completion suggestions are requested.

Recently we've seen some performance problems in code completion, and after some investigation we're now looking into a more radical change to the protocol. We're basically investigating using a protocol similar to the one LSP defines. The new protocol would allow the server to send back a small portion of the total list, allowing the client to control how much of the list should be returned.

If that work is successful, not only should it improve performance, but it should also allow us to compute suggestions from un-imported libraries when completions are requested, which should then allow us to include suggestions for extension members.

Thanks for the offer to help. I'm not the primary developer working on the new protocol, so I'm not sure how you could best contribute. I think that most of the work in the analysis server is completed and now we're working on finishing the work on the client side so that we can start testing it end-to-end.

shinayser commented 2 years ago

Those are amazing news @bwilkerson. We're very excited to see the result of all your efforts!

I am a completion maniac myself, so if you folks need some guy like me to test that stuff, just call me :)

srawlins commented 2 years ago

@scheglov can you confirm you implemented this?

scheglov commented 2 years ago

Works for me.

  1. Completion.

    image
  2. Quick fix.

    image
JulianBissekkou commented 2 years ago

Thanks to everybody that was involved in this feature. It works really smooth 👍🏽

naamapps commented 2 years ago

Hi, How can I get to use this feature? I'm using vscode with latest flutter and Dart plug-in versions but this doesn't seem to work for me. Do I need to set a setting or update something? Thanks

scheglov commented 2 years ago

As you can see, I use IntelliJ, but at least quick fix should work in VS Code as well. Does it work for you?

naamapps commented 2 years ago

Sorry, I must have missed that. Yes the quick fix is working, but autocomplete doesn't work. Can we expect autocomplete to arrive to vscode soon?

scheglov commented 2 years ago

@DanTup for VS Code completion insides :-)

shinayser commented 2 years ago

@scheglov do we need to update dart to some specific version to get this working?

scheglov commented 2 years ago

The changes, at least for quick fixes, were done in 979f3ea79ee188ec2e0c039a3186ebd28e0f636c. And for code completions about the same time. So, I expect that these are available in 2.17 Dart.

shinayser commented 2 years ago

Ok I tested and it worked on some scenarios.

I believe I know why I haven't realized that change before and that is because our dependencies are transient.

I have a module that imports a dependencies module, and because of that the extensions doesn't work. Was it an intended behavior?

DanTup commented 2 years ago

@shinayser my understanding is that this is intended. Any packages you directly depend on should be listed in your pubspec.yaml (so you can set constraints and ensure they're always available even if other dependencies stop depending on them). As a result, completion/fixes/etc. will only suggest from those packages (if it didn't, code completion would contain a large number of classes from transient dependencies that not be wanted).

There's a related lint at https://dart-lang.github.io/linter/lints/depend_on_referenced_packages.html.

naamapps commented 2 years ago

@DanTup Any news about this feature arriving to vscode? :)

DanTup commented 2 years ago

@naamapps the quick-fix should already work today. Showing up in the completion list and auto-importing requires using a new completion API so isn't available in stable yet, although it is working behind a flag in the latest bleeding-edge/master SDK builds:

Screenshot 2022-07-25 at 11 30 30

I'm not ready to make it default/remove the flag yet (I've still been fixing some issues fairly recently), but it's getting there.

naamapps commented 2 years ago

Thanks for the quick reply @DanTup. Looking forward to use this feature 👍

Adrian-Samoticha commented 2 years ago

@naamapps the quick-fix should already work today. Showing up in the completion list and auto-importing requires using a new completion API so isn't available in stable yet, although it is working behind a flag in the latest bleeding-edge/master SDK builds:


I'm not ready to make it default/remove the flag yet (I've still been fixing some issues fairly recently), but it's getting there.

This is great to hear. I'm looking forward to using this feature as well.

shinayser commented 2 years ago

@shinayser my understanding is that this is intended. Any packages you directly depend on should be listed in your pubspec.yaml (so you can set constraints and ensure they're always available even if other dependencies stop depending on them). As a result, completion/fixes/etc. will only suggest from those packages (if it didn't, code completion would contain a large number of classes from transient dependencies that not be wanted).

There's a related lint at https://dart-lang.github.io/linter/lints/depend_on_referenced_packages.html.

Thanks for your reply! I understand your point but it is a common pattern on some monorepo architectures to concentrate all the dependencies on a common "dependencies" module. So we would never get code completion on larger products because of this limitation.

You think I should open another issue to report that? Maybe we could think on a different solution. Maybe adding s tag to the pubspec to include those dependencies to the auto complete algorithm?

DanTup commented 2 years ago

@shinayser there's some similar discussion at https://github.com/dart-lang/sdk/issues/43678#issuecomment-847782349. The suggestion was allowing the "common dependencies module" to record which of its dependencies it exposes to packages that depend on it. The response was that this should be filed against Pub, although I can't see any obvious issue that was raised about this, so perhaps it's worth filing one there to start a discussion.