Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lint for used package not defined in pubspec #29

Closed
kevmoo opened this issue Feb 14, 2015 · 40 comments · Fixed by #2659
Closed

Lint for used package not defined in pubspec #29

kevmoo opened this issue Feb 14, 2015 · 40 comments · Fixed by #2659
Assignees
Labels
category-pub contributions-welcome Contributions welcome to help resolve this (the resolution is expected to be clear from the issue) lint-request type-enhancement A request for a change that isn't a bug

Comments

@kevmoo
Copy link
Member

kevmoo commented Feb 14, 2015

No description provided.

@kevmoo kevmoo changed the title Link for used package not defined in pubspec Lint for used package not defined in pubspec Feb 14, 2015
@pq pq added the type-enhancement A request for a change that isn't a bug label Feb 15, 2015
@pq
Copy link
Member

pq commented Feb 15, 2015

Silly question: but wouldn't this result in a compilation error?

@kevmoo
Copy link
Member Author

kevmoo commented Feb 15, 2015

If you specify X which depends on Y you can depend on Y.

But if X later removes its dependency on Y, you'll be borked.

@sethladd
Copy link

Are we supposed to list all transitive dependencies in our pubspec ?

@kevmoo
Copy link
Member Author

kevmoo commented Feb 15, 2015

@sethladd: absolutely not.

We should have an explicit dependency for libraries with explicitly use.

@sethladd
Copy link

ah, yes! gotcha :)

@kevmoo
Copy link
Member Author

kevmoo commented Mar 6, 2018

Is this doable? @pq @alexeieleusis @a14n ?

T'would make many folks very happy

@kevmoo kevmoo added the contributions-welcome Contributions welcome to help resolve this (the resolution is expected to be clear from the issue) label Mar 6, 2018
@bwilkerson
Copy link
Member

We can certainly compute the information you're interested in. When linting each compilation unit, look for explicit references to elements defined in packages that are not explicitly depended on. We might need to cache the list of explicit dependencies somewhere to improve performance.

What about implicit references? For example, given a.b.c, if a is defined in package A, and b returns a class from a package B, do you want to create a lint for the use of c if there is no explicit dependency on B?

@kevmoo
Copy link
Member Author

kevmoo commented Mar 6, 2018

@bwilkerson – let's keep things crazy simple

If

import 'package:a/a.dart';
// or
export 'package:a/a.dart';

And a is not a dependency defined in pubspec.yaml – dependencies or dev_dependencies – then generate a lint.

@kevmoo
Copy link
Member Author

kevmoo commented Mar 6, 2018

...if the import/export directive is in a file in lib then the dependency had better be in dependencies (not just dev_dependencies)

@zoechi
Copy link

zoechi commented Mar 6, 2018

Is there a way to exclude code from that? For example when I want to share code between test/ and example or as I had it in Flutter between test/ and test_driver/
I don't want to add dependencies used there to dependencies
It's not super important, but worth a thought.

@kevmoo
Copy link
Member Author

kevmoo commented Mar 6, 2018 via email

@kevmoo
Copy link
Member Author

kevmoo commented Mar 6, 2018 via email

@zoechi
Copy link

zoechi commented Mar 6, 2018

so if I have import 'package:uuid/uuid.dart'; in lib/test/id_generator.dart
and I import that in test/foo_test.dart and test_driver/foo_integration_test.dart
using import 'package:my_package/test/id_generator.dart';
would this need to be a dependency, or would be dev_dependency be enough?

@bwilkerson
Copy link
Member

Every library inside of lib can be referenced by any package that depends on your package via a package: URI. That means that someone else could import id_generator.dart in their production code. In order for that to not break, you'd need to include a non-dev dependency on uuid in your pubspec. If you don't want other packages to reference id_generator.dart, then you should move the file outside of lib.

@zoechi
Copy link

zoechi commented Mar 7, 2018

@bwilkerson but there is no valid way to import it from somewhere else, or is there?
Otherwise I would if course put it somewhere else.
Is import '../test_shared/id_generator.dart'; ok in test/foo_test.dart?

@bwilkerson
Copy link
Member

but there is no valid way to import it from somewhere else, or is there?

If you publish a package foo, that contains a file at the path foo/lib/test/bar.dart, then any other package can add your package to their pubspec and can import 'package:foo/test/bar.dart';. Everything inside lib is potentially accessible, even src.

It's only by convention that other developers are expected to not reference code inside lib/src, and I've never seen any convention for code inside lib/test. Code that is outside of lib cannot be accessed via a package: URI.

Is import '../test_shared/id_generator.dart'; ok in test/foo_test.dart?

Yes. Relative paths like this can reach any file and will work correctly for anyone that clones your repository as long as the path doesn't include directories outside your repository. We strongly discourage using relative paths inside of lib that include directories outside of lib. (And I personally discourage using relative paths anywhere inside of lib because it minimizes the possibility of subtle bugs related to mixing import styles.)

@zoechi
Copy link

zoechi commented Mar 7, 2018

Yes. Relative paths like this can reach any file and will work correctly

It's only for importing from other top-level directories inside the same package like test, test_driver, example, ...
It's a bit ugly, but should do because it's not too common.

@pq
Copy link
Member

pq commented Sep 10, 2019

The hint here might be a good idea, to lower expectations :-)

Agreed!

Thanks for following up. 👍

@ditman
Copy link
Member

ditman commented Feb 5, 2020

We've recently received at least a bug report in Flutter web where the user was using a transitive dependency (which was web only) in their Flutter app, and was wondering why their application was not compiling on Android.

We're not sure how the "include" ended up in their code, but it might have been the user manually inputting it.

I think a hint on the import statement letting you know that you're using a package which you don't depend on directly would be great.

What needs to be done to write an efficient hint/lint? I have some experience with the AST visitors in @pq's tools; I expect something similar?

@pq
Copy link
Member

pq commented Feb 6, 2020

Thanks for the added context @ditman. Very useful!

@bwilkerson: putting aside API implications for a moment, is this something we can derive from an imported library's Namespace?

@bwilkerson
Copy link
Member

No, the namespace for an imported library contains all of the top-level names that are either defined in that library or are exported from other libraries by that library.

What we'll need to do is parse the pubspec.yaml file to find the immediate dependencies and then look for any package: URIs that reference a package that isn't in that list. In order to be efficient we'll want to cache the results of the parse so that we don't need to re-parse it for every file in a package.

While the import certainly might have been hand entered, it's also possible for it to have been added automatically by server. I can think of several possibilities, and there are probably several I'm not thinking of:

  • code completing a symbol from a library in such a package,
  • adding an override of a method defined in such a package, and
  • using an assist like "add type annotation".

If we add this lint we should consider adding a quick fix that adds an explicit dependency to the pubspec.yaml file (though getting the version constraints correct might be tricky).

@ditman
Copy link
Member

ditman commented Feb 6, 2020

If we add this lint we should consider adding a quick fix that adds an explicit dependency to the pubspec.yaml file (though getting the version constraints correct might be tricky).

@bwilkerson If it were possible to know the version of the transient dependency, it'd probably be nice to set the version to that (or ^version).

@bwilkerson
Copy link
Member

Agreed. We might be able to scrape the current version from the path in the .pub-cache (assuming that's where the package lives).

@pq
Copy link
Member

pq commented Feb 6, 2020

@bwilkerson and I chatted and I see a path forward that would add support to LinterContext to query for dependencies. This would benefit at least avoid_web_libraries_in_flutter and make other analyses possible.

@ditman
Copy link
Member

ditman commented Feb 7, 2020

Please, do reach out to me if I can be of any help! Thanks for considering this!

@pq
Copy link
Member

pq commented Feb 7, 2020

https://dart-review.googlesource.com/c/sdk/+/134861

(Adds a pubspec getter to PubWorkspacePackages.)

dart-bot pushed a commit to dart-lang/sdk that referenced this issue Feb 7, 2020
See: dart-lang/linter#29

Change-Id: Ifcd4ad359a43c9183ab42ed6bb0ebb3586c73afd
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/134861
Commit-Queue: Phil Quitslund <[email protected]>
Reviewed-by: Brian Wilkerson <[email protected]>
@pq
Copy link
Member

pq commented Feb 13, 2020

Having thought about this some more, are we sure we want to limit this to pubspec dependencies?

That is, are we likely to want similar behavior for BazelWorkspacePackages or do we not have the same transitive closure issue there? (cc @srawlins, @davidmorgan)

/fyi @jacob314

@bwilkerson
Copy link
Member

We do have the same issues, but they're handled by the build system. It would be better to have a development time diagnostic rather than a build time error, but at least it gets caught, unlike in the pub case.

@jakemac53
Copy link
Contributor

I am curious what the status of this is - it is somewhat common to forget to add deps until you try to pub lish which has a warning for it. I would much prefer to catch this before that point, so an analyzer hint/lint would be great.

@pq
Copy link
Member

pq commented Sep 22, 2020

This is one of I think many opportunities for improvement wrt pub and analysis.

/fyi @jonasfj

@jakemac53
Copy link
Contributor

jakemac53 commented Sep 22, 2020

One idea for how this could be implemented would be to have pub add its own field to the package_config.json with this information (list of direct deps) - and then internally we could do the same based on the build rules. Although I think that wouldn't help the IDE experience still internally.

@FufferKS
Copy link

Hi, any update on this issue?

@pq
Copy link
Member

pq commented May 19, 2021

Sorry, no real progress.

@FufferKS: if you have any other context or experience to share, it'd be welcome. Is this an issue that you hit frequently? How does it impact you?

Thanks for chiming in!

@FufferKS
Copy link

I'm running into this issue pretty much on a daily bases.

I'm working on a fairly large project that's separated into a number of packages. All of those depend on a "common" package with some core logic. The "common" package also depends on a number of public packages - bloc, etc. When working on any of the concrete packages, there is no hinting of e.q. bloc related classes.
This is a bit simplified, in reality the dependency tree of ours is even deeper.

This forces me to make imports by hand, which is quite cumbersome.

@pq
Copy link
Member

pq commented May 19, 2021

This is useful, thanks! Is the project open-source? (No worries if not but if it is, it would be useful for us to look at the structure to better understand how this and related issues are impacting folks.)

@FufferKS
Copy link

Thanks for the answers :)

The project is not open source, here is an obscured project dependency tree. Each entry is a separate flutter project.
image

@pq pq closed this as completed in #2659 May 19, 2021
@pq
Copy link
Member

pq commented May 21, 2021

Awesome. Thanks for this @FufferKS!

/fyi @jakemac53

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
category-pub contributions-welcome Contributions welcome to help resolve this (the resolution is expected to be clear from the issue) lint-request type-enhancement A request for a change that isn't a bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants