-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
[analyzer_plugin]: setContextRoots event never received #56475
Comments
Summary: The |
Note that this is a regression, and it completely breaks analyzer_plugins in this scenario. So this is fairly important IMO |
Debugging this in 3.5, I think there is a race condition. Haven't compared to master yet, but documenting it here while I have it in my head. There's code here for It starts the plugin if it's not already started, and then it calls However, in the bad case, it appears we run this code twice for the same plugin/root at approximately the same time: In this case, the first call starts setting up the plugin and waits for it (so it can then add the root), but the second request comes in and skips most of the method (because Then when the first call finishes starting the plugin and tries to add the root, it finds the root has already been added (even though the plugin wasn't notified because it wasn't fully started at the time) so it skips adding the root (and therefore notifying the plugin). The reason we're calling this multiple times is because
(Edit: The below was incorrect, applying that cherry-pick did not fix the issue)
|
I suspect that nobody considered the impact of the multiple-analysis-options-per-context work on plugins. I know that I didn't. I suspect that even if |
The cherry-pick above didn't solve the issue - I think it was coincidence I initially didn't see it on master, it certainly reproduces when I'm running from source with my additional debug logging. Changing the We can perhaps fix this by having 1724079379402:Info:adding plugins custom_lint to C::\Dev\Temp Projects\analyzer_plugin_bug_repro However as far as I can tell, https://github.com/dart-lang/sdk/blob/3.5.0/pkg/analyzer/lib/src/dart/analysis/driver.dart#L349-L353 |
Yeah, I think you're right that this wouldn't work and probably we should only look at the analysis_options at the root of the package instead.
Edit: nm that, this project is one that doesn't have an analysis_options and doesn't have the plugin. So I think this issue is explained by looking at the entire tree of analysis_options instead of only the one for the context (eg. this project shouldn't have the plugin at all, but it's getting it from the flattened analysis options of the whole project). |
I don't think "package"s have anything to do with it because the algorithm that determines where the analysis contexts are doesn't take package boundaries into consideration.
That doesn't match my understanding of how things are suppose to work now, so if that's how they're actually working that does sound like a bug. For one thing, there isn't suppose to be any concept of "the flattened analysis options of the whole project". Every library (technically file, but we never access the options for a part) knows the options that should be used when analyzing it. The most consistent semantics would be for any library for which a plugin |
Right, so I think this code here is wrong? https://github.com/dart-lang/sdk/blob/3.5.0/pkg/analyzer/lib/src/dart/analysis/driver.dart#L349-L353 It seems to read all enable plugins from every project, so for the root folder in your workspace, it tries to enable every plugin from every nested project (which is both incorrect, and includes dupes). If I change that code like this: Then it appears to solve the problem - we only look at the analysis options for the root of that context (although it seems odd to use the analysis options file path to get the appropriate file path). I don't know if this is a good fix or whether it has other mismatches though. The additional race I noted above when a plugin exists for multiple drivers still occurs, but turns out to not actually be a problem because when the first context finishes initializing the plugin, it re-sends all roots (not only the one it was adding), so this "race" has probably existed forever and isn't actually impacting anything. However, I'm less sure that this "fix" above works for Pub workspaces, because if I understand correctly, that's when we may have a single context/driver that spans multiple projects and/or analysis_options, in which case I think the nested projects would not be able to have their own plugins enabled - although I'm also unsure if that is a problem or an expectation (I think it's not clear to me what the definition of "context root" in the plugin API really means in a Pub workspace). |
Also:
I'm a little confused by this. I thought contexts were where pubspec.yaml or analysis_options.yaml are (so not a perfect match, but close) - however looking at the code it seems like I think I know less about this than I assumed. In particular it's not clear to me:
(if the answers to these already exist somewhere I should have read, I'm happy to be pointed there instead of just given the answers!) |
^ These are questions I've asked myself too. I think
|
(I'm not sure what you mean by "project", but I'm assuming you mean "the directory that was opened in the IDE".) Yes, that's wrong.
As far as I'm aware,
It doesn't match the semantics I think we want. 🙂
Right. The semantics I described earlier we intended for that situation (though I think they also nicely handle the non-workspace case as well). Although, in all fairness, the semantics I gave were ignoring the fact that we will only load a single plugin. Given that restriction, I think the right algorithm is to iterate over all of the analysis options files (as it's doing now), and look for enabled plugins. When it finds the first enabled plugin it needs to remember the path of the plugin and the set of files in the directory containing the analysis options file that are to be analyzed. After that it can ignore analysis options files that don't enable the one chosen plugin, and add the included and excluded files if the options file does enable the plugin.
The first part used to be true, but we should now only be creating a context when we find a
That isn't what I would have expected. @keertip
They are the information about where to create an analysis context that is gathered before we create any actual contexts. There's a 1-to-1 correspondence between a context root and an analysis context.
Good question. It used to, but I don't know whether that was preserved in the workspace support because I don't think anyone considered the impact on plugins. It probably shouldn't match anymore because of the way I'd like to see plugin enablement work (see the next paragraph), but I'm open to other designs than the one I proposed.
I think that the UX would be best if users could enable plugins for any subset of an analysis context. I'd do that by allowing them to enable plugins in any analysis options file and use the location of the options file to build the included and excluded lists sent to the plugin. That seems consistent with the way the rest of the analysis options work. That definition would also minimize the number of changes that users have to make to their options files in order to use a workspace. |
Sorry, I meant "package" (eg. a think with a pubspec that has some name). In C#, these were called "Projects" (and a workspace of multiple projects was a "Solution") and I often use package and project interchangeably (but try to use
Ok, let me debug why that's happening and I can open a separate issue if it seems like something is wrong there.
Currently it appears that we can't pass an include list to a plugin. When we call I think this means we'll need to track "plugin roots" specifically so that if a plugin is added to an analysis_options file, the plugin is notified of that new root even though it didn't change any server context roots? I'm not up-to-speed with the plugin changes that were in progress - is this something that makes sense to try and handle now, or when that work is further along (@srawlins?). And since this is a much larger change than could be cherry-picked, do we need to do anything about this issue for 3.5? (it's not currently clear to me if there is an easy fix that restores the previous behaviour and I'm less sure now that the change I made above matches the previous behaviour (or whether doing something like that is sound anyway). |
Sorry, this was user error. I see many contexts when I open my "analysis server workspace" because it's a multi-root workspace. So when I tested, I closed that and opened the I just verified with bleeding-edge opening the |
No, my suggestion was based on a faulty memory of what information we could pass to the plugin.
That is probably the right long term solution. I just don't know whether it makes sense to try to do that in the short term.
I'm not ready to answer that question because I don't understand either the problem or the solution well enough at this point. We're also taking a look at it. |
This adds failing tests for #56475. If this CL is applied to the 3.5 release and the `singleOptionContexts` flag set back to `true` (matching 3.4 behaviour), the tests will pass. Each package in both tests will get its own context root (because they have analysis_options to enable the plugins) and each one will read the correct plugins that are enabled. However if `singleOptionContexts` is `false` (as shipped in 3.5) or this code is applied to bleeding-edge (where the flag is gone, but behaves the same as `false`) both tests fail as follows: `test_sentToPlugins_inNestedPackages_withPackageConfigs` fails because we read the child analysis_options for the root and try to incorrectly load plugins from the root (and include duplicates and allow more than one plugin): ``` Expected: { 'package1': ['plugin1'], 'package2': ['plugin2'], 'package3': ['plugin1'] } Actual: { 'home': ['plugin1', 'plugin2', 'plugin1'], 'package1': ['plugin1', 'plugin2', 'plugin1'], 'package2': ['plugin1', 'plugin2', 'plugin1'], 'package3': ['plugin1'] } ``` `test_sentToPlugins_inNestedPackages_withoutPackageConfigs` fails because we now only have a context root for the root which enables all plugins from the children: ``` Expected: { 'package1': ['plugin1'], 'package2': ['plugin2'], 'package3': ['plugin1'] } Actual: { 'home': ['plugin1', 'plugin2', 'plugin1'] } ``` Change-Id: I12f45eeb5c1848352af26ac3fdb690e51833c22a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/381460 Commit-Queue: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Samuel Rawlins <srawlins@google.com>
…r having wrong roots) This is a cherry-pick of a76ff6b and c0c697b which resolves an issue where analysis server plugins may not receive `setContextRoots` requests or may receive the wrong context roots due to the changes to not create an analysis context for every folder containing an `analysis_options.yaml` file. This change forces an analysis context for each folder that changes the set of plugins that are enabled compared to its parent, so that each "plugin root" is once again an analysis context root. Bug: #56475 Change-Id: Ia561d7ecf7429711a1059b0d77fc1929629b75cc Cherry-pick: https://dart-review.googlesource.com/c/sdk/+/381460 Cherry-pick: https://dart-review.googlesource.com/c/sdk/+/381481 Cherry-pick: https://dart-review.googlesource.com/c/sdk/+/381860 Cherry-pick-request: #56547 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/381760 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Samuel Rawlins <srawlins@google.com> Reviewed-by: Phil Quitslund <pquitslund@google.com> Commit-Queue: Alexander Thomas <athom@google.com>
The fix for this issue was included in Dart 3.5.2 (released last week) and Flutter 3.24.2 (release today). |
Hello!
TL;DR, in certain situation, the
setContextRoots
event is never received by plugins.I'm not sure what exactly triggers it, so I made a reproduction repository. It is composed of:
It is the bare minimum for a plugin, with no logic in it besides extending
ServerPlugin
.They are composed if nothing but pubspec.yamls and maybe a pubspec_overrides.yaml
The reproduction repository is here: https://github.com/rrousselGit/analyzer_plugin_bug_repro
Steps to reproduce:
path: /Users/remirousselet/dev/rrousselGit/fake_riverpod/packages/custom_lint
and replace it with an absolute path that points topackages/custom_lint
dart pub get
everywhere (the IDE should suggest it)In the logs, you will see some requests made to the analyzer plugin. Such as:
But there's never a
analysis.setContextRoots
request sent by default.Note:
If you restart the analyzer server while the plugin is running, and override
ServerPlugin.handleAnalysisSetContextRoots
to log somewhere in a while,you will see that the method is invoked right before
shutdown
is invoked.It is hard to see in the analyzer logs, because the request appears in the log right
before the log file is cleared.
Dart SDK version: 3.5.0 (stable) (Tue Jul 30 02:17:59 2024 -0700) on "macos_arm64"
The text was updated successfully, but these errors were encountered: